;>*******************************************************************************************************************************
;*																																*
;*	File:	Render.asm																											*
;*																																*
;*	This file defines constants, code, and data for the rendering of the neurons.												*
;*																																*
;<*******************************************************************************************************************************

include	Render.inc
include	sse3.inc

CalculateAcceleration			proto
CalculateAccelerationSlow		proto

;>*******************************************************************************************************************************
;*																																*
;*	Section:	Circles																											*
;*																																*
;*	This section contains definitions for various circles in terms of 8x8 grids of intensities from 0 to 1						*
;*																																*
;<*******************************************************************************************************************************

.data

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	Circle4																											*
;*																																*
;*	Top half of a circle of diameter 4 pixels, centred in an 8x8 grid.															*
;*																																*
;<*******************************************************************************************************************************
align	16
Circle4	WORD	0,0,000h,000h,000h,000h,0,0
		WORD	0,0,000h,000h,000h,000h,0,0
		WORD	0,0,03Ch,0E8h,0E8h,03Ch,0,0
		WORD	0,0,0E8h,100h,100h,0E8h,0,0

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	Circle5																											*
;*																																*
;*	Top half of a circle of diameter 5 pixels, centred in an 8x8 grid.															*
;*																																*
;<*******************************************************************************************************************************
align	16
Circle5	WORD	0,0,000h,000h,000h,000h,000h,0
		WORD	0,0,020h,0C0h,100h,0C0h,020h,0
		WORD	0,0,0C0h,100h,100h,100h,0C0h,0
		WORD	0,0,100h,100h,100h,100h,100h,0

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	Circle6																											*
;*																																*
;*	Top half of a circle of diameter 6 pixels, centred in an 8x8 grid.															*
;*																																*
;<*******************************************************************************************************************************
align	16
Circle6	WORD	0,000h,000h,000h,000h,000h,000h,0
		WORD	0,000h,088h,0F8h,0F8h,088h,000h,0
		WORD	0,088h,100h,100h,100h,100h,088h,0
		WORD	0,0F8h,100h,100h,100h,100h,0F8h,0

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	Circle7																											*
;*																																*
;*	Top half of a circle of diameter 7 pixels, centred in an 8x8 grid.															*
;*																																*
;<*******************************************************************************************************************************
align	16
Circle7	WORD	0,000h,04Ch,0CCh,0F4h,0CCh,04Ch,000h
		WORD	0,04Ch,100h,100h,100h,100h,100h,04Ch
		WORD	0,0CCh,100h,100h,100h,100h,100h,0CCh
		WORD	0,0F4h,100h,100h,100h,100h,100h,0F4h

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	Circle8																											*
;*																																*
;*	Top half of a circle of diameter 8 pixels, centred in an 8x8 grid.															*
;*																																*
;<*******************************************************************************************************************************
align	16
Circle8	WORD	000h,030h,0B8h,0F0h,0F0h,0B8h,030h,000h
		WORD	030h,0F4h,100h,100h,100h,100h,0F4h,030h
		WORD	0B8h,100h,100h,100h,100h,100h,100h,0B8h
		WORD	0F0h,100h,100h,100h,100h,100h,100h,0F0h


;>*******************************************************************************************************************************
;*																																*
;*	Section:	Data																											*
;*																																*
;*																																*
;<*******************************************************************************************************************************

.data

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	ViewInverse																										*
;*																																*
;*	This is a 4x4 matrix that represents the transformation from world coordinates to view coordinates.							*
;*																																*
;<*******************************************************************************************************************************
align	16
ViewInverse	VECTOR	<1.0, 0.0, 0.0, 0.0>
			VECTOR	<0.0, 1.0, 0.0, 0.0>
			VECTOR	<0.0, 0.0, 1.0, 0.0>
			VECTOR	<0.0, 0.0, 0.0, 1.0>

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	ViewPosition																									*
;*																																*
;*																																*
;<*******************************************************************************************************************************
align	16
ViewPosition	VECTOR	<0.0, 0.0, 20.0, 0.0>

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	ViewVelocity																									*
;*																																*
;*																																*
;<*******************************************************************************************************************************
align	16
ViewVelocity	VECTOR	<0.5, 0.3, 0.7, 0.0>

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	ViewRight																										*
;*																																*
;*																																*
;<*******************************************************************************************************************************
align	16
ViewRight	VECTOR	<1.0, 0.0, 0.0, 0.0>

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	ForceConstant																									*
;*																																*
;*	This is 4 copies of the same scalar, not actually a vector.																	*
;*																																*
;<*******************************************************************************************************************************
align	16
ForceConstant	VECTOR	<0.5, 0.5, 0.5, 0.5>

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	ViewInverseOrbitA																								*
;*																																*
;*	This is a 4x4 matrix that represents the transformation from orbit A neuron coordinates to world coordinates to view		*
;*	coordinates.																												*
;*																																*
;<*******************************************************************************************************************************
align	16
ViewInverseOrbitA	VECTOR	<1.0, 0.0, 0.0, 0.0>
					VECTOR	<0.0, 1.0, 0.0, 0.0>
					VECTOR	<0.0, 0.0, 1.0, 0.0>
					VECTOR	<0.0, 0.0, 0.0, 1.0>

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	OrbitAPosition																									*
;*																																*
;*																																*
;<*******************************************************************************************************************************
align	16
OrbitAPosition	VECTOR	<20.0, 20.0, 0.0, 0.0>

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	OrbitARight																										*
;*																																*
;*																																*
;<*******************************************************************************************************************************
align	16
OrbitARight	VECTOR	<1.0, 0.0, 0.0, 0.0>

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	OrbitAVelocity																									*
;*																																*
;*																																*
;<*******************************************************************************************************************************
align	16
OrbitAVelocity	VECTOR	<-0.5, -0.3, -0.4, 0.0>

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	ScreenFactor																									*
;*																																*
;*	This is 4 copies of the number of pixels (in the intermediate buffer) from the centre to 45 degrees out (i.e. x/z=1 or		*
;*	y/z=1).																														*
;*																																*
;<*******************************************************************************************************************************
align	16
ScreenFactor	VECTOR	<400.0, 400.0, 400.0, 400.0>

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	ViewInverseOrbitB																								*
;*																																*
;*	This is a 4x4 matrix that represents the transformation from orbit B neuron coordinates to world coordinates to view		*
;*	coordinates.																												*
;*																																*
;<*******************************************************************************************************************************
align	16
ViewInverseOrbitB	VECTOR	<1.0, 0.0, 0.0, 0.0>
					VECTOR	<0.0, 1.0, 0.0, 0.0>
					VECTOR	<0.0, 0.0, 1.0, 0.0>
					VECTOR	<0.0, 0.0, 0.0, 1.0>

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	OrbitBPosition																									*
;*																																*
;*																																*
;<*******************************************************************************************************************************
align	16
OrbitBPosition	VECTOR	<-15.0, -15.0, -15.0, 0.0>

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	OrbitBRight																										*
;*																																*
;*																																*
;<*******************************************************************************************************************************
align	16
OrbitBRight	VECTOR	<1.0, 0.0, 0.0, 0.0>

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	OrbitBVelocity																									*
;*																																*
;*																																*
;<*******************************************************************************************************************************
align	16
OrbitBVelocity	VECTOR	<-0.5, 0.3, 0.4, 0.0>

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	AllNegativeOne																									*
;*																																*
;*	This is 4 copies of the number -1.0.																						*
;*																																*
;<*******************************************************************************************************************************
align	16
AllNegativeOne	VECTOR	<-1.0, -1.0, -1.0, -1.0>

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	TempVectors																										*
;*																																*
;*	This is just a place to store temporary vectors.																			*
;*																																*
;<*******************************************************************************************************************************
align	16
TempVectors	VECTOR	8 dup (<>)

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	AllOne																											*
;*																																*
;*	This is 4 copies of the number 1.0.																							*
;*																																*
;<*******************************************************************************************************************************
align	16
AllOne	VECTOR	<1.0, 1.0, 1.0, 1.0>

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	AllHalf																											*
;*																																*
;*	This is 4 copies of the number 0.5.																							*
;*																																*
;<*******************************************************************************************************************************
align	16
AllHalf	VECTOR	<0.5, 0.5, 0.5, 0.5>

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	AllNegative256																									*
;*																																*
;*	This is 4 copies of -256.0.																									*
;*																																*
;<*******************************************************************************************************************************
align	16
AllNegative256	VECTOR	<-256.0, -256.0, -256.0, -256.0>

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	GlowAmountFactor																								*
;*																																*
;*																																*
;<*******************************************************************************************************************************
align	16
GlowAmountFactor	VECTOR	<96.0,96.0,96.0,96.0>

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	BlueMask																										*
;*																																*
;*																																*
;<*******************************************************************************************************************************
align	16
BlueMask	DWORD_VECTOR	<0FFh,0FFh,0FFh,0FFh>

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	ZeroOneTwoThree																									*
;*																																*
;*																																*
;<*******************************************************************************************************************************
align	16
ZeroOneTwoThree	VECTOR	<0.0,1.0,2.0,3.0>

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	NotBlueMask																										*
;*																																*
;*																																*
;<*******************************************************************************************************************************
align	16
NotBlueMask	DWORD_VECTOR	<0FFFF00h,0FFFF00h,0FFFF00h,0FFFF00h>

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	LowGlowFactor																									*
;*																																*
;*																																*
;<*******************************************************************************************************************************
align	16
LowGlowFactor	VECTOR	<0.375,0.375,0.375,0.375>

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	GlowIntensityLimit																								*
;*																																*
;*																																*
;<*******************************************************************************************************************************
align	16
GlowIntensityLimit	DWORD_VECTOR	<180,180,180,180>

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	GlowIntensityLimitPlus1																							*
;*																																*
;*																																*
;<*******************************************************************************************************************************
align	16
GlowIntensityLimitPlus1	DWORD_VECTOR	<181,181,181,181>

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	AllOneFixedPoint																								*
;*																																*
;*	This is 8 copies of the number 1.0 in 8.8 fixed-point format.																*
;*																																*
;<*******************************************************************************************************************************
align	16
AllOneFixedPoint	WORD_VECTOR	<0100h,0100h,0100h,0100h,0100h,0100h,0100h,0100h>

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	AllHalfFixedPoint																								*
;*																																*
;*	This is 8 copies of the number 0.5 in 8.8 fixed-point format.																*
;*																																*
;<*******************************************************************************************************************************
align	16
AllHalfFixedPoint	WORD_VECTOR	<0080h,0080h,0080h,0080h,0080h,0080h,0080h,0080h>

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	LastElementOne																									*
;*																																*
;*	This has 3 elements zero, and the last element one.  It can be used for making points compatible with full matrix			*
;*	transformation.																												*
;*																																*
;<*******************************************************************************************************************************
align	16
LastElementOne	VECTOR	<0.0, 0.0, 0.0, 1.0>

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	AllZero																											*
;*																																*
;*	This has 4 elements that are all zero.																						*
;*																																*
;<*******************************************************************************************************************************
align	16
AllZero	VECTOR	<0.0, 0.0, 0.0, 0.0>

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	DeltaReds																										*
;*																																*
;*	This is 8 copies of the red component of colour B (C) minus the red component of colour A (B), all times 2.					*
;*																																*
;<*******************************************************************************************************************************
align	16
DeltaReds	WORD_VECTOR	<2*(RED_B-RED_A),2*(RED_C-RED_B),2*(RED_B-RED_A),2*(RED_C-RED_B),2*(RED_B-RED_A),2*(RED_C-RED_B),2*(RED_B-RED_A),2*(RED_C-RED_B)>

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	DeltaGreens																										*
;*																																*
;*	This is 8 copies of the green component of colour B (C) minus the green component of colour A (B), all times 2.				*
;*																																*
;<*******************************************************************************************************************************
align	16
DeltaGreens	WORD_VECTOR	<2*(GREEN_B-GREEN_A),2*(GREEN_C-GREEN_B),2*(GREEN_B-GREEN_A),2*(GREEN_C-GREEN_B),2*(GREEN_B-GREEN_A),2*(GREEN_C-GREEN_B),2*(GREEN_B-GREEN_A),2*(GREEN_C-GREEN_B)>

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	DeltaBlues																										*
;*																																*
;*	This is 8 copies of the blue component of colour B (C) minus the blue component of colour A (B), all times 2.				*
;*																																*
;<*******************************************************************************************************************************
align	16
DeltaBlues	WORD_VECTOR	<2*(BLUE_B-BLUE_A),2*(BLUE_C-BLUE_B),2*(BLUE_B-BLUE_A),2*(BLUE_C-BLUE_B),2*(BLUE_B-BLUE_A),2*(BLUE_C-BLUE_B),2*(BLUE_B-BLUE_A),2*(BLUE_C-BLUE_B)>

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	RedA																											*
;*																																*
;*	This is 8 copies of the red component of colour A, minus the red component of DeltaBC.										*
;*																																*
;<*******************************************************************************************************************************
align	16
RedA	WORD_VECTOR	<RED_A+RED_B-RED_C,RED_A+RED_B-RED_C,RED_A+RED_B-RED_C,RED_A+RED_B-RED_C,RED_A+RED_B-RED_C,RED_A+RED_B-RED_C,RED_A+RED_B-RED_C,RED_A+RED_B-RED_C>

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	GreenA																											*
;*																																*
;*	This is 8 copies of the green component of colour A, minus the green component of DeltaBC.									*
;*																																*
;<*******************************************************************************************************************************
align	16
GreenA	WORD_VECTOR	<GREEN_A+GREEN_B-GREEN_C,GREEN_A+GREEN_B-GREEN_C,GREEN_A+GREEN_B-GREEN_C,GREEN_A+GREEN_B-GREEN_C,GREEN_A+GREEN_B-GREEN_C,GREEN_A+GREEN_B-GREEN_C,GREEN_A+GREEN_B-GREEN_C,GREEN_A+GREEN_B-GREEN_C>

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	BlueA																											*
;*																																*
;*	This is 8 copies of the blue component of colour A, minus the blue component of DeltaBC.									*
;*																																*
;<*******************************************************************************************************************************
align	16
BlueA	WORD_VECTOR	<BLUE_A+BLUE_B-BLUE_C,BLUE_A+BLUE_B-BLUE_C,BLUE_A+BLUE_B-BLUE_C,BLUE_A+BLUE_B-BLUE_C,BLUE_A+BLUE_B-BLUE_C,BLUE_A+BLUE_B-BLUE_C,BLUE_A+BLUE_B-BLUE_C,BLUE_A+BLUE_B-BLUE_C>

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	NeuronCentrePoints																								*
;*																																*
;*	These are the centre points of the 44 neurons in the cube.																	*
;*																																*
;<*******************************************************************************************************************************
align	16
NeuronCentrePoints	VECTOR	<-10.0, -10.0, -10.0, 0.0>
					VECTOR	<10.0, -10.0, -10.0, 0.0>
					VECTOR	<-10.0, 10.0, -10.0, 0.0>
					VECTOR	<10.0, 10.0, -10.0, 0.0>
					VECTOR	<-5.0, -10.0, -10.0, 0.0>
					VECTOR	<-5.0, 10.0, -10.0, 0.0>
					VECTOR	<-10.0, -5.0, -10.0, 0.0>
					VECTOR	<10.0, -5.0, -10.0, 0.0>
					VECTOR	<0.0, -10.0, -10.0, 0.0>
					VECTOR	<0.0, 10.0, -10.0, 0.0>
					VECTOR	<-10.0, 0.0, -10.0, 0.0>
					VECTOR	<10.0, 0.0, -10.0, 0.0>
					VECTOR	<5.0, -10.0, -10.0, 0.0>
					VECTOR	<5.0, 10.0, -10.0, 0.0>
					VECTOR	<-10.0, 5.0, -10.0, 0.0>
					VECTOR	<10.0, 5.0, -10.0, 0.0>
					VECTOR	<-10.0, -10.0, 10.0, 0.0>
					VECTOR	<10.0, -10.0, 10.0, 0.0>
					VECTOR	<-10.0, 10.0, 10.0, 0.0>
					VECTOR	<10.0, 10.0, 10.0, 0.0>
					VECTOR	<-5.0, -10.0, 10.0, 0.0>
					VECTOR	<-5.0, 10.0, 10.0, 0.0>
					VECTOR	<-10.0, -5.0, 10.0, 0.0>
					VECTOR	<10.0, -5.0, 10.0, 0.0>
					VECTOR	<0.0, -10.0, 10.0, 0.0>
					VECTOR	<0.0, 10.0, 10.0, 0.0>
					VECTOR	<-10.0, 0.0, 10.0, 0.0>
					VECTOR	<10.0, 0.0, 10.0, 0.0>
					VECTOR	<5.0, -10.0, 10.0, 0.0>
					VECTOR	<5.0, 10.0, 10.0, 0.0>
					VECTOR	<-10.0, 5.0, 10.0, 0.0>
					VECTOR	<10.0, 5.0, 10.0, 0.0>
					VECTOR	<-10.0, -10.0, 5.0, 0.0>
					VECTOR	<10.0, -10.0, 5.0, 0.0>
					VECTOR	<-10.0, 10.0, 5.0, 0.0>
					VECTOR	<10.0, 10.0, 5.0, 0.0>
					VECTOR	<-10.0, -10.0, 0.0, 0.0>
					VECTOR	<10.0, -10.0, 0.0, 0.0>
					VECTOR	<-10.0, 10.0, 0.0, 0.0>
					VECTOR	<10.0, 10.0, 0.0, 0.0>
					VECTOR	<-10.0, -10.0, -5.0, 0.0>
					VECTOR	<10.0, -10.0, -5.0, 0.0>
					VECTOR	<-10.0, 10.0, -5.0, 0.0>
					VECTOR	<10.0, 10.0, -5.0, 0.0>

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	NeuronGraph																										*
;*																																*
;*																																*
;<*******************************************************************************************************************************
align	4
NeuronGraph	DWORD	4,6,40
			DWORD	7,12,41
			DWORD	5,14,42
			DWORD	13,15,43
			DWORD	0,8,-1
			DWORD	2,9,-1
			DWORD	0,10,-1
			DWORD	1,11,-1
			DWORD	4,12,-1
			DWORD	5,13,-1
			DWORD	6,14,-1
			DWORD	7,15,-1
			DWORD	1,8,-1
			DWORD	3,9,-1
			DWORD	2,10,-1
			DWORD	3,11,-1
			DWORD	20,22,32
			DWORD	23,28,33
			DWORD	21,30,34
			DWORD	29,31,35
			DWORD	16,24,-1
			DWORD	18,25,-1
			DWORD	16,26,-1
			DWORD	17,27,-1
			DWORD	20,28,-1
			DWORD	21,29,-1
			DWORD	22,30,-1
			DWORD	23,31,-1
			DWORD	17,24,-1
			DWORD	19,25,-1
			DWORD	18,26,-1
			DWORD	19,27,-1
			DWORD	16,36,-1
			DWORD	17,37,-1
			DWORD	18,38,-1
			DWORD	19,39,-1
			DWORD	32,40,-1
			DWORD	33,41,-1
			DWORD	34,42,-1
			DWORD	35,43,-1
			DWORD	0,36,-1
			DWORD	1,37,-1
			DWORD	2,38,-1
			DWORD	3,39,-1

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	pIntermediateBuffer																								*
;*																																*
;*	This points to the intermediate buffer, an array of floats representing the current transparency of the corresponding point	*
;*	in the image buffer.  On the beginning of each render, this is initialized to all 1's.										*
;*																																*
;*	See Also:																													*
;*		- <Intermediate Buffer Dimensions>																						*
;*																																*
;<*******************************************************************************************************************************
align	4
pIntermediateBuffer	DWORD	?

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	CurrentQ																										*
;*																																*
;*																																*
;<*******************************************************************************************************************************
align	4
CurrentQ	Real4	0.0

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	CurrentR																										*
;*																																*
;*																																*
;<*******************************************************************************************************************************
align	4
CurrentR	Real4	0.0

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	GoalQ																											*
;*																																*
;*																																*
;<*******************************************************************************************************************************
align	4
GoalQ	Real4	?

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	GoalR																											*
;*																																*
;*																																*
;<*******************************************************************************************************************************
align	4
GoalR	Real4	?

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	pPoints																											*
;*																																*
;*	This points to the array of 4-float vectors that are the points in the cube and both orbitting neurons.						*
;*																																*
;<*******************************************************************************************************************************
align	4
pPoints	DWORD	?

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	pPointsQ																										*
;*																																*
;*	This points to the array of 4-float vectors that are the points in the cube and both orbitting neurons in configuration Q.	*
;*																																*
;<*******************************************************************************************************************************
align	4
pPointsQ	DWORD	?

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	pPointsR																										*
;*																																*
;*	This points to the array of 4-float vectors that are the points in the cube and both orbitting neurons in configuration R.	*
;*																																*
;<*******************************************************************************************************************************
align	4
pPointsR	DWORD	?

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	pPointsS																										*
;*																																*
;*	This points to the array of 4-float vectors that are the points in the cube and both orbitting neurons in configuration S.	*
;*																																*
;<*******************************************************************************************************************************
align	4
pPointsS	DWORD	?

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	pScreenPoints																									*
;*																																*
;*	This points to the array of the form x0,y0,x1,y1,z0,z0,z1,z1,x2,y2,x3,y3,z2,z2,z3,z3,... after they have been transformed	*
;*	into screen coordinates.																									*
;*																																*
;<*******************************************************************************************************************************
align	4
pScreenPoints	DWORD	?

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	pWeights																										*
;*																																*
;*	This points to the array of floats that are the weights (between 0 and 1) of the points in the cube and both orbitting		*
;*	neurons.																													*
;*																																*
;<*******************************************************************************************************************************
align	4
pWeights	DWORD	?

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	pWeightsQ																										*
;*																																*
;*	This points to the array of floats that are the weights (between 0 and 1) of the points in the cube and both orbitting		*
;*	neurons in configuration Q.																									*
;*																																*
;<*******************************************************************************************************************************
align	4
pWeightsQ	DWORD	?

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	pWeightsR																										*
;*																																*
;*	This points to the array of floats that are the weights (between 0 and 1) of the points in the cube and both orbitting		*
;*	neurons in configuration R.																									*
;*																																*
;<*******************************************************************************************************************************
align	4
pWeightsR	DWORD	?

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	pWeightsS																										*
;*																																*
;*	This points to the array of floats that are the weights (between 0 and 1) of the points in the cube and both orbitting		*
;*	neurons in configuration S.																									*
;*																																*
;<*******************************************************************************************************************************
align	4
pWeightsS	DWORD	?

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	QRSDistanceStep																									*
;*																																*
;*	The amount to adjust Q, R, and S, in one frame.																				*
;*																																*
;*	They form the unit triangle, so a value of more than 1.0 has the same effect as the value 1.0 (i.e. completely random		*
;*	configurations).																											*
;*																																*
;<*******************************************************************************************************************************
align	4
QRSDistanceStep	Real4	0.04

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	RecipQRSDistanceStep																							*
;*																																*
;*	The reciprocal of <QRSDistanceStep>.																						*
;*																																*
;<*******************************************************************************************************************************
align	4
RecipQRSDistanceStep	Real4	25.0

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	CircleSizeFactor																								*
;*																																*
;*	This is the Factor in: CircleSize = (Factor*Weight/z)+4.  It is currently -0.3765*200/1.5.									*
;*																																*
;<*******************************************************************************************************************************
align	4
CircleSizeFactor	Real4	-354.139

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	GlowSizeFactors																									*
;*																																*
;*	This is the Factor in: GlowSize = (Factor/z).																				*
;*																																*
;<*******************************************************************************************************************************
align	4
GlowSizeFactors	Real4	-3000.0
				Real4	-2950.0
				Real4	-2850.0
				Real4	-2700.0
				Real4	-2500.0
				Real4	-2300.0
				Real4	-2150.0
				Real4	-2050.0
				Real4	-2000.0
				Real4	-2050.0
				Real4	-2150.0
				Real4	-2300.0
				Real4	-2500.0
				Real4	-2700.0
				Real4	-2850.0
				Real4	-2950.0

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	GlowSizeIndex																									*
;*																																*
;*																																*
;<*******************************************************************************************************************************
align	4
GlowSizeIndex	DWORD	0

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	ViewEnergy																										*
;*																																*
;*																																*
;<*******************************************************************************************************************************
align	4
ViewEnergy	Real4	-0.55241107940673828125

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	OrbitAEnergy																									*
;*																																*
;*																																*
;<*******************************************************************************************************************************
align	4
OrbitAEnergy	Real4	-0.38389408588409423828125

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	OrbitBEnergy																									*
;*																																*
;*																																*
;<*******************************************************************************************************************************
align	4
OrbitBEnergy	Real4	-0.46649754047393798828125

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	GlowIndices																										*
;*																																*
;*	These are the indices of the 6 neurons in the cube that are currently glowing.												*
;*																																*
;<*******************************************************************************************************************************
align	4
GlowIndices	DWORD	0,4,8,12,1,7

;>*******************************************************************************************************************************
;*																																*
;*	Variable:	pRenderRandom																									*
;*																																*
;*																																*
;<*******************************************************************************************************************************
align	4
pRenderRandom	DWORD	?


;>*******************************************************************************************************************************
;*																																*
;*	Section:	Code																											*
;*																																*
;*																																*
;<*******************************************************************************************************************************

.code

;>*******************************************************************************************************************************
;*																																*
;*	Function:	RenderImage																										*
;*																																*
;*	This function renders the image of the neurons into <pImageBuffer>.															*
;*																																*
;<*******************************************************************************************************************************
RenderImage	proc
	push	ebx
	push	esi
	push	edi
	
;Before dealing with the points, take the linear combination of Q, R, and S points to make the current points.
	xor		eax,eax
	movss	xmm0,CurrentQ			;xmm0 = Q
	movss	xmm1,CurrentR			;xmm1 = R
	movss	xmm2,AllOne.x			;xmm2 = 1-Q-R = S
	subss	xmm2,xmm0				;
	subss	xmm2,xmm1				;
	shufps	xmm0,xmm0,00000000b		;xmm0 = Q,Q,Q,Q
	shufps	xmm1,xmm1,00000000b		;xmm1 = R,R,R,R
	shufps	xmm2,xmm2,00000000b		;xmm2 = S,S,S,S
	mov		ebx,pPointsQ
	mov		ecx,pPointsR
	mov		edx,pPointsS
	mov		edi,pPoints
NextLinearCombination:
	movaps	xmm3,[ebx][eax]
	movaps	xmm4,[ecx][eax]
	movaps	xmm5,[edx][eax]
	mulps	xmm3,xmm0
	mulps	xmm4,xmm1
	mulps	xmm5,xmm2
	addps	xmm3,xmm4
	addps	xmm3,xmm5
	movaps	[edi][eax],xmm3
	add		eax,10h
	cmp		eax,NUM_TOTAL_POINTS*10h
	jne		NextLinearCombination
	xor		eax,eax
	mov		ebx,pWeightsQ
	mov		ecx,pWeightsR
	mov		edx,pWeightsS
	mov		edi,pWeights
NextLinearCombinationWeights:		;This loop does 4 weights at a time
	movaps	xmm3,[ebx][eax]
	movaps	xmm4,[ecx][eax]
	movaps	xmm5,[edx][eax]
	mulps	xmm3,xmm0
	mulps	xmm4,xmm1
	mulps	xmm5,xmm2
	addps	xmm3,xmm4
	addps	xmm3,xmm5
	movaps	[edi][eax],xmm3
	add		eax,10h
	cmp		eax,NUM_TOTAL_POINTS*4
	jb		NextLinearCombinationWeights


;First, take the points and transform them to screen coordinates.
	mov		ecx,NUM_CUBE_POINTS
	mov		eax,pPoints
	mov		edx,pScreenPoints
	mov		ebx,offset ViewInverse
	cmp		isSSE3Supported,TRUE
	jne		TransformWithNoSSE3
	call	TransformPoints
	mov		ecx,NUM_ORBITA_POINTS
	mov		ebx,offset ViewInverseOrbitA
	call	TransformPoints
	mov		ecx,NUM_ORBITB_POINTS
	mov		ebx,offset ViewInverseOrbitB
	call	TransformPoints
	jmp		DoneTransformPoints
TransformWithNoSSE3:
	call	TransformPointsSlow
	mov		ecx,NUM_ORBITA_POINTS
	mov		ebx,offset ViewInverseOrbitA
	call	TransformPointsSlow
	mov		ecx,NUM_ORBITB_POINTS
	mov		ebx,offset ViewInverseOrbitB
	call	TransformPointsSlow
DoneTransformPoints:
	
IF TIMING
	mov		ecx,1
	call	RecordTime
ENDIF

;Set the Intermediate Buffer to all 1.0
;	mov		eax,pIntermediateBuffer
;	movdqa	xmm0,AllOneFixedPoint
;	mov		edx,IMAGE_HEIGHT*IMAGE_WIDTH*2/80h
;	jmp		ClearBufferLoopEntry
;ALIGN 16
;ClearMoreBuffer:					;Clear 128 bytes (32 floats) on each iteration
;	add		eax,80h
;ClearBufferLoopEntry:
;	sub		edx,1
;	movdqa	[eax][00h],xmm0			;movdqa is the most efficient way,
;	movdqa	[eax][10h],xmm0			;since the processor will do a full cache line store
;	movdqa	[eax][20h],xmm0			;at a time (64 bytes)
;	movdqa	[eax][30h],xmm0
;	movdqa	[eax][40h],xmm0
;	movdqa	[eax][50h],xmm0
;	movdqa	[eax][60h],xmm0
;	movdqa	[eax][70h],xmm0
;	jnz		ClearMoreBuffer
	mov		edi,pIntermediateBuffer			;This is an alternative means of clearing the buffer
	mov		eax,00FF00FFh					;and it may or may not be faster in general.
	mov		ecx,IMAGE_HEIGHT*IMAGE_WIDTH/2	;
	rep stosd								;
	
IF TIMING
	mov		ecx,2
	call	RecordTime
ENDIF

;Apply the Circles to the Intermediate Buffer.
	mov		eax,pScreenPoints
ASSUME EAX:PTR POINT2D
	mov		esi,pWeights
	mov		ecx,NUM_TOTAL_POINTS
NextCircle:
	mov		ebx,[eax].x
	mov		edx,[eax].y
	imul	edx,edx,IMAGE_WIDTH
	lea		edi,[eax+10h+sizeof POINT2D]
	add		eax,sizeof POINT2D
	test	eax,0Fh					;On every second point,
	cmovz	eax,edi					;skip over the 1/z coordinates
	movss	xmm0,[esi]
	add		esi,4
	cmp		dword ptr [edi-sizeof POINT2D],0	;If the z coordinate (or more precisely the 1/z coordinate)
	jg		CheckNextCircle			;is positive, skip it.
	cmp		ebx,-(IMAGE_WIDTH/2) + 4
	jl		CheckNextCircle
	cmp		ebx,(IMAGE_WIDTH/2) - 4
	jg		CheckNextCircle
	cmp		edx,-(IMAGE_WIDTH*IMAGE_HEIGHT/2) + (4*IMAGE_WIDTH)
	jl		CheckNextCircle
	cmp		edx,(IMAGE_WIDTH*IMAGE_HEIGHT/2) - (4*IMAGE_WIDTH)
	jg		CheckNextCircle
	shufps	xmm0,xmm0,00000000b
	movaps	xmm6,xmm0
	mulps	xmm6,AllNegative256
	cvtps2dq	xmm6,xmm6
	packssdw	xmm6,xmm6
	movdqa	xmm7,AllOneFixedPoint
	mulss	xmm0,[edi-sizeof POINT2D]		;xmm0 = weight/z
	mov		edi,pIntermediateBuffer
	add		edx,ebx
	lea		edx,[edi][edx*2 + IMAGE_WIDTH*IMAGE_HEIGHT + IMAGE_WIDTH - 2*IMAGE_WIDTH*4 - 2*4]
	mulss	xmm0,CircleSizeFactor			;xmm0 = factor*weight/z
	cvtss2si	ebx,xmm0					;ebx = (int)(factor*weight/z)
	mov		edi,4							;Make sure that ebx is at most 4
	cmp		ebx,4							;
	cmova	ebx,edi							;
	shl		ebx,6							;Then, make it a multiple of 40h, because that's the size of each circle data chunk.
ASSUME EBX:PTR VECTOR
;Apply a whole circle with 8.8 fixed-point numbers
;xmm6 contains 8 copies of the current weight
;xmm7 contains 8 copies of 1.0 in fixed-point
	movdqa	xmm0,Circle4[ebx+00h]		;xmm0 = c00 to c07 in 8.8
	movdqa	xmm1,Circle4[ebx+10h]		;xmm1 = c10 to c17 in 8.8
	movdqa	xmm2,Circle4[ebx+20h]		;xmm2 = c20 to c27 in 8.8
	movdqa	xmm3,Circle4[ebx+30h]		;xmm3 = c30 to c37 in 8.8
	pmullw	xmm0,xmm6					;xmm0 = -w*c00 to -w*c07 in 0.16
	pmullw	xmm1,xmm6					;xmm1 = -w*c10 to -w*c17 in 0.16
	pmullw	xmm2,xmm6					;xmm2 = -w*c20 to -w*c27 in 0.16
	pmullw	xmm3,xmm6					;xmm3 = -w*c30 to -w*c37 in 0.16
	psraw	xmm0,8						;xmm0 = -w*c00 to -w*c07 in 8.8
	psraw	xmm1,8						;xmm1 = -w*c10 to -w*c17 in 8.8
	psraw	xmm2,8						;xmm2 = -w*c20 to -w*c27 in 8.8
	psraw	xmm3,8						;xmm3 = -w*c30 to -w*c37 in 8.8
	paddw	xmm0,xmm7					;xmm0 = 1-w*c00 to 1-w*c07 in 8.8
	movdqu	xmm4,[edx]					;xmm4 = t00 to t07 in 8.8
	paddw	xmm1,xmm7					;xmm1 = 1-w*c10 to 1-w*c17 in 8.8
	movdqu	xmm5,[edx][1*2*IMAGE_WIDTH]	;xmm5 = t10 to t17 in 8.8
	paddw	xmm2,xmm7					;xmm2 = 1-w*c20 to 1-w*c27 in 8.8
	movdqu	xmm6,[edx][2*2*IMAGE_WIDTH]	;xmm6 = t20 to t27 in 8.8
	paddw	xmm3,xmm7					;xmm0 = 1-w*c30 to 1-w*c37 in 8.8
	movdqu	xmm7,[edx][3*2*IMAGE_WIDTH]	;xmm7 = t30 to t37 in 8.8
	pmullw	xmm4,xmm0					;xmm4 = t00*(1-w*c00) to t07*(1-w*c07) in 0.16
	pmullw	xmm5,xmm1					;xmm5 = t10*(1-w*c10) to t17*(1-w*c17) in 0.16
	pmullw	xmm6,xmm2					;xmm6 = t20*(1-w*c20) to t27*(1-w*c27) in 0.16
	pmullw	xmm7,xmm3					;xmm7 = t30*(1-w*c30) to t37*(1-w*c37) in 0.16
	psrlw	xmm4,8						;xmm4 = t00*(1-w*c00) to t07*(1-w*c07) in 8.8
	psrlw	xmm5,8						;xmm5 = t10*(1-w*c10) to t17*(1-w*c17) in 8.8
	psrlw	xmm6,8						;xmm6 = t20*(1-w*c20) to t27*(1-w*c27) in 8.8
	psrlw	xmm7,8						;xmm7 = t30*(1-w*c30) to t37*(1-w*c37) in 8.8
	movdqu	[edx],xmm4
	movdqu	[edx][1*2*IMAGE_WIDTH],xmm5
	movdqu	[edx][2*2*IMAGE_WIDTH],xmm6
	movdqu	[edx][3*2*IMAGE_WIDTH],xmm7
;The bottom half can reuse the values in xmm0 to xmm3 because the circle is symmetrical vertically
	movdqu	xmm4,[edx][4*2*IMAGE_WIDTH]	;xmm4 = t40 to t47 in 8.8
	movdqu	xmm5,[edx][5*2*IMAGE_WIDTH]	;xmm5 = t50 to t57 in 8.8
	movdqu	xmm6,[edx][6*2*IMAGE_WIDTH]	;xmm6 = t60 to t67 in 8.8
	movdqu	xmm7,[edx][7*2*IMAGE_WIDTH]	;xmm7 = t70 to t77 in 8.8
	pmullw	xmm4,xmm3					;xmm4 = t40*(1-w*c40) to t47*(1-w*c47) in 0.16
	pmullw	xmm5,xmm2					;xmm5 = t50*(1-w*c50) to t57*(1-w*c57) in 0.16
	pmullw	xmm6,xmm1					;xmm6 = t60*(1-w*c60) to t67*(1-w*c67) in 0.16
	pmullw	xmm7,xmm0					;xmm7 = t70*(1-w*c70) to t77*(1-w*c77) in 0.16
	psrlw	xmm4,8						;xmm4 = t40*(1-w*c40) to t47*(1-w*c47) in 8.8
	psrlw	xmm5,8						;xmm5 = t50*(1-w*c50) to t57*(1-w*c57) in 8.8
	psrlw	xmm6,8						;xmm6 = t60*(1-w*c60) to t67*(1-w*c67) in 8.8
	psrlw	xmm7,8						;xmm7 = t70*(1-w*c70) to t77*(1-w*c77) in 8.8
	movdqu	[edx][4*2*IMAGE_WIDTH],xmm4
	movdqu	[edx][5*2*IMAGE_WIDTH],xmm5
	movdqu	[edx][6*2*IMAGE_WIDTH],xmm6
	movdqu	[edx][7*2*IMAGE_WIDTH],xmm7
CheckNextCircle:
	sub		ecx,1
	jnz		NextCircle
ASSUME EAX:NOTHING,EBX:NOTHING

IF TIMING
	mov		ecx,3
	call	RecordTime
ENDIF

;Convert the Intermediate Buffer to RGB Values in the Image Buffer
	mov			ecx,pIntermediateBuffer
	mov			edx,pImageBuffer
	xor			eax,eax
	movdqa		xmm7,DeltaBlues
NextOctRGB:
	movdqa		xmm0,[ecx][eax]		;Calculate 8 RGB triplets at a time
	add			eax,10h
	movdqa		xmm6,xmm0
	pminsw		xmm0,AllHalfFixedPoint
	pmaxsw		xmm6,AllHalfFixedPoint
	movdqa		xmm1,xmm0
	movdqa		xmm2,xmm0
	movdqa		xmm3,xmm0
	movdqa		xmm4,xmm0
	movdqa		xmm5,xmm0
	punpcklwd	xmm0,xmm6
	punpckhwd	xmm1,xmm6
	punpcklwd	xmm2,xmm6
	punpckhwd	xmm3,xmm6
	punpcklwd	xmm4,xmm6
	punpckhwd	xmm5,xmm6
	
	movdqa		xmm6,DeltaReds
	
	pmaddwd		xmm0,xmm7	;DeltaBlues
	pmaddwd		xmm1,xmm7	;DeltaBlues
	pmaddwd		xmm2,DeltaGreens
	pmaddwd		xmm3,DeltaGreens
	pmaddwd		xmm4,xmm6	;DeltaReds
	pmaddwd		xmm5,xmm6	;DeltaReds
	psrad		xmm0,8
	psrad		xmm1,8
	psrad		xmm2,8
	psrad		xmm3,8
	psrad		xmm4,8
	psrad		xmm5,8
	packssdw	xmm0,xmm1		;xmm0 = b0' to b7'
	packssdw	xmm2,xmm3		;xmm2 = g0' to g7'
	packssdw	xmm4,xmm5		;xmm4 = r0' to r7'
	paddw		xmm0,BlueA		;xmm0 = b0 to b7
	paddw		xmm2,GreenA		;xmm2 = g0 to g7
	paddw		xmm4,RedA		;xmm4 = r0 to r7

	cmp			eax,IMAGE_WIDTH*IMAGE_HEIGHT*2

	movdqa		xmm1,xmm0
	movdqa		xmm5,xmm4
	punpcklwd	xmm0,xmm2		;xmm0 = b0,g0,b1,g1,b2,g2,b3,g3
	punpckhwd	xmm1,xmm2		;xmm1 = b4,g4,b5,g5,b6,g6,b7,g7
	punpcklwd	xmm4,xmm4		;xmm4 = r0,r0,r1,r1,r2,r2,r3,r3
	punpckhwd	xmm5,xmm5		;xmm5 = r4,r4,r5,r5,r6,r6,r7,r7
	packuswb	xmm0,xmm1		;xmm0 = b0,g0,b1,g1,b2,g2,b3,g3,...,b7,g7
	packuswb	xmm4,xmm5		;xmm4 = r0,r0,r1,r1,r2,r2,r3,r3,...,r7,r7
	movdqa		xmm2,xmm0		;xmm2 = b0,g0,b1,g1,b2,g2,b3,g3,...,b7,g7
	punpcklwd	xmm0,xmm4		;xmm0 = b0,g0,r0,r0,b1,g1,r1,r1,b2,g2,r2,r2,b3,g3,r3,r3
	punpckhwd	xmm2,xmm4		;xmm2 = b4,g4,r4,r4,b5,g5,r5,r5,b6,g6,r6,r6,b7,g7,r7,r7

	movdqa		[edx][eax*2-20h],xmm0
	movdqa		[edx][eax*2-10h],xmm2

	jne			NextOctRGB

IF TIMING
	mov		ecx,4
	call	RecordTime
ENDIF

;Calculate the positions of the neurons that are glowing
	mov			edi,pScreenPoints
	mov			eax,GlowIndices[0]
	mov			ecx,GlowIndices[4]
	mov			edx,GlowIndices[8]
	mov			esi,GlowIndices[12]
	shl			eax,4
	shl			ecx,4
	shl			edx,4
	shl			esi,4
	movaps		xmm0,NeuronCentrePoints[eax]
	movaps		xmm1,NeuronCentrePoints[ecx]
	movaps		xmm2,NeuronCentrePoints[edx]
	movaps		xmm3,NeuronCentrePoints[esi]
	addps		xmm0,LastElementOne
	addps		xmm1,LastElementOne
	addps		xmm2,LastElementOne
	addps		xmm3,LastElementOne
	movaps		[edi][00h],xmm0
	movaps		[edi][10h],xmm1
	movaps		[edi][20h],xmm2
	movaps		[edi][30h],xmm3
	mov			eax,edi
	mov			eax,GlowIndices[16]
	mov			ecx,GlowIndices[20]
	shl			eax,4
	shl			ecx,4
	movaps		xmm0,NeuronCentrePoints[eax]
	movaps		xmm1,NeuronCentrePoints[ecx]
	movaps		xmm2,OrbitAPosition
	movaps		xmm3,OrbitBPosition
	addps		xmm0,LastElementOne
	addps		xmm1,LastElementOne
	addps		xmm2,LastElementOne
	addps		xmm3,LastElementOne
	movaps		[edi][40h],xmm0
	movaps		[edi][50h],xmm1
	movaps		[edi][60h],xmm2
	movaps		[edi][70h],xmm3
	mov			eax,edi
	mov			ebx,offset ViewInverse
	mov			ecx,8
	lea			edx,[edi+80h]
	cmp			isSSE3Supported,TRUE
	jne			TransformGlowWithNoSSE3
	call		TransformPoints
	jmp			DoneTransformGlow
TransformGlowWithNoSSE3:
	call		TransformPointsSlow
DoneTransformGlow:

	lea		eax,[edi+80h]
	mov		ecx,8
	movdqa	xmm7,BlueMask
NextGlowPoint:
	push	ecx
	mov		ebx,[eax].POINT2D.x
	mov		edx,[eax].POINT2D.y
	lea		edi,[eax+10h+sizeof POINT2D]
	add		eax,sizeof POINT2D
	test	eax,0Fh					;On every second point,
	cmovz	eax,edi					;skip over the 1/z coordinates
	push	eax
	cmp		dword ptr [edi-sizeof POINT2D],0	;If the z coordinate (or more precisely, the 1/z coordinate)
	jg		CheckNextGlowPoint		;is positive, skip it.
	mov		eax,GlowSizeIndex
	movss	xmm0,[edi-sizeof POINT2D]		;xmm0 = 1/z
	mulss	xmm0,GlowSizeFactors[eax*4]		;xmm0 = factor/z = GlowLimit
	cvtss2si	ecx,xmm0					;ecx = (int)GlowLimit
	add		ebx,IMAGE_WIDTH/2
	add		edx,IMAGE_HEIGHT/2
	mulss	xmm0,xmm0						;xmm0 = GlowLimit^2
	rcpss	xmm0,xmm0						;xmm0 = 1/GlowLimit^2
	mulss	xmm0,dword ptr GlowAmountFactor	;xmm0 = f/GlowLimit^2
	shufps	xmm0,xmm0,00000000b
	xor		edi,edi							;edi = 0
	mov		esi,IMAGE_WIDTH					;esi = IMAGE_WIDTH
	mov		eax,edx							;eax = y
	sub		eax,ecx							;eax = y-GlowLimit
	cmovs	eax,edi							;eax = max(y-GlowLimit,0) = y0
	mov		edi,eax							;edi = y0
IF IMAGE_WIDTH NE 1024
	.err <Since IMAGE_WIDTH is no longer 1024, the following line needs to change in order to multiply eax by IMAGE_WIDTH.>
ENDIF
	shl		eax,10
;The problem with multiplying eax by esi is that edx also gets modified, unless a certain form of imul is used instead
;	mul		esi								;eax = y0*IMAGE_WIDTH
	sub		edi,edx							;edi = y0-y
	add		eax,ebx							;eax = y0*IMAGE_WIDTH+x
	sub		esi,ebx							;esi = IMAGE_WIDTH-x
	shl		eax,2							;eax = 4*(y0*IMAGE_WIDTH+x)
	add		eax,pImageBuffer				;eax = pImageBuffer+4*(y0*IMAGE_WIDTH+x)
	neg		edx								;edx = -y
	cmp		esi,ecx							;esi = x1-x = min(GlowLimit,IMAGE_WIDTH-x)
	cmovg	esi,ecx							;
	add		edx,IMAGE_HEIGHT				;edx = IMAGE_HEIGHT-y
	cmp		edx,ecx							;edx = y1-y = min(GlowLimit,IMAGE_HEIGHT-y)
	cmovg	edx,ecx							;
	neg		ecx
	add		ecx,ebx							;ecx = x-GlowLimit
	neg		ebx								;ebx = -x
	and		ecx,not 3h						;ecx = (x-GlowLimit)&(~3)
	add		ecx,ebx							;ecx = ((x-GlowLimit)&(~3))-x
	cmp		ecx,ebx							;ecx = x0-x = max((x-GlowLimit)&(~3),0)-x
	cmovl	ecx,ebx							;
NextGlowLine:
	cmp		edi,edx
	jge		CheckNextGlowPoint
	cvtsi2ss	xmm1,edi					;xmm1 = dy
	mulss		xmm1,xmm1					;xmm1 = dy^2
	shufps		xmm1,xmm1,00000000b			;xmm1 = dy^2,dy^2,dy^2,dy^2
	mov		ebx,ecx
NextGlowPixels:
	cmp		ebx,esi
	jge		CheckNextGlowLine
	cvtsi2ss	xmm2,ebx					;xmm2 = dx
	shufps		xmm2,xmm2,00000000b			;xmm2 = dx,dx,dx,dx
	addps		xmm2,ZeroOneTwoThree		;xmm2 = dx,dx+1,dx+2,dx+3
	xorps		xmm4,xmm4					;xmm4 = 0
	mulps		xmm2,xmm2					;xmm2 = dx^2,(dx+1)^2,(dx+2)^2,(dx+3)^2
	addps		xmm2,xmm1					;xmm2 = dx^2+dy^2,(dx+1)^2+dy^2,(dx+2)^2+dy^2,(dx+3)^2+dy^2 = d^2,d'^2,d''^2,d'''^2
	mulps		xmm2,xmm0					;xmm2 = f*d^2/GlowLimit^2
	movaps		xmm3,GlowAmountFactor		;xmm3 = f
	subps		xmm3,xmm2					;xmm3 = f-(f*d^2/GlowLimit^2)
	maxps		xmm3,xmm4					;xmm3 = GlowAmount = max(f-(f*d^2/GlowLimit^2),0)
	movdqa		xmm4,[eax+ebx*4]			;xmm4 = Original = pImageBuffer[y0*IMAGE_WIDTH+x+dx]
	movdqa		xmm2,xmm4					;xmm2 = Original
	pand		xmm4,xmm7					;xmm4 = OriginalGlow = Original & BlueMask
	pand		xmm2,NotBlueMask			;xmm4 = OriginalExtra
	movdqa		xmm6,xmm4					;xmm6 = OriginalGlow
	cvtdq2ps	xmm4,xmm4					;xmm4 = (float)OriginalGlow
	movaps		xmm5,xmm4					;xmm5 = (float)OriginalGlow
	minps		xmm4,xmm3					;xmm4 = LowGlow = min(GlowAmount,OriginalGlow)
	maxps		xmm5,xmm3					;xmm5 = HighGlow = max(GlowAmount,OriginalGlow)
	mulps		xmm4,LowGlowFactor			;xmm4 = g*LowGlow
	addps		xmm4,xmm5					;xmm4 = HighGlow+g*LowGlow
	cvtps2dq	xmm4,xmm4					;xmm4 = (int)(HighGlow+g*LowGlow)
	pminsw		xmm4,xmm7					;xmm4 = FinalGlow = min(HighGlow+g*LowGlow,0FFh), Although this is for signed words, it should work in this case.
	
	movdqa		xmm3,GlowIntensityLimit		;xmm3 = 180
	pxor		xmm5,xmm5					;xmm5 = 0
	psubd		xmm3,xmm4					;xmm3 = 180-FinalGlow
	pcmpgtd		xmm5,xmm3					;xmm5 = 0FFFFFFFFh if 0>180-FinalGlow, else 0
	pand		xmm5,xmm3					;xmm5 = 180-FinalGlow if 0>180-FinalGlow, else 0
	movdqa		xmm3,GlowIntensityLimitPlus1;xmm3 = 181
	pcmpgtd		xmm3,xmm6					;xmm3 = 0FFFFFFFFh if 181>OriginalGlow, else 0
	pand		xmm3,xmm5					;xmm3 = 180-FinalGlow if FinalGlow>180 && OriginalGlow<=180, else 0
	paddd		xmm4,xmm3					;xmm4 = 180 if FinalGlow>180 && OriginalGlow<=180, else FinalGlow
	
	
	
	
	por			xmm4,xmm2
	movdqa		[eax+ebx*4],xmm4
	add		ebx,4
	jmp		NextGlowPixels
CheckNextGlowLine:
	add		edi,1
	add		eax,IMAGE_WIDTH*4
	jmp		NextGlowLine
CheckNextGlowPoint:
	pop		eax
	pop		ecx
	sub		ecx,1
	jnz		NextGlowPoint

	pop		edi
	pop		esi
	pop		ebx
	ret
RenderImage	endp

;>*******************************************************************************************************************************
;*																																*
;*	Function:	TransformPoints																									*
;*																																*
;*	Transforms an array of points by a given matrix and then into screen coordinates.											*
;*																																*
;*	Parameters:																													*
;*	eax	- address of the array of points																						*
;*	ebx	- address of the matrix																									*
;*	ecx	- number of points to transform																							*
;*	edx	- address of destination array																							*
;*																																*
;*	Returns:																													*
;*	eax	- end of the array of input points																						*
;*	edx	- end of the array of output points																						*
;*																																*
;<*******************************************************************************************************************************
TransformPoints	proc
NextCubePoint:
	movaps	xmm0,[eax][00h]			;xmm0 = P0
	movaps	xmm1,[eax][10h]			;xmm1 = P1
	movaps	xmm2,[eax][20h]			;xmm2 = P2
	movaps	xmm3,[eax][30h]			;xmm3 = P3
	add		eax,40h
; Process 4 x's
	movaps	xmm4,[ebx][00h]			;xmm4 = Matrix[x]
	movaps	xmm5,xmm4				;xmm5 = Matrix[x]
	movaps	xmm6,xmm4				;xmm6 = Matrix[x]
	movaps	xmm7,xmm4				;xmm7 = Matrix[x]
	mulps	xmm4,xmm0				;xmm4 = P0 * Matrix[x]
	mulps	xmm5,xmm1				;xmm5 = P1 * Matrix[x]
	mulps	xmm6,xmm2				;xmm6 = P2 * Matrix[x]
	mulps	xmm7,xmm3				;xmm7 = P3 * Matrix[x]
	haddps	xmm4,xmm5
; Process 4 y's
	movaps	xmm5,[ebx][10h]			;xmm5 = Matrix[y]
	haddps	xmm6,xmm7
	movaps	xmm7,xmm5				;xmm7 = Matrix[y]
	haddps	xmm4,xmm6				;xmm4 = x0',x1',x2',x3'
	movaps	xmm6,xmm5				;xmm6 = Matrix[y]
	movaps	TempVectors[00h],xmm4
	movaps	xmm4,xmm5				;xmm4 = Matrix[y]
	mulps	xmm5,xmm0				;xmm5 = P0 * Matrix[y]
	mulps	xmm7,xmm1				;xmm7 = P1 * Matrix[y]
	mulps	xmm6,xmm2				;xmm6 = P2 * Matrix[y]
	mulps	xmm4,xmm3				;xmm4 = P3 * Matrix[y]
	haddps	xmm5,xmm7
; Process 4 z's
	movaps	xmm7,[ebx][20h]			;xmm7 = Matrix[z]
	haddps	xmm6,xmm4
	movaps	xmm4,xmm7				;xmm4 = Matrix[z]
	haddps	xmm5,xmm6				;xmm5 = y0',y1',y2',y3'
	movaps	xmm6,xmm7				;xmm6 = Matrix[z]
	movaps	TempVectors[10h],xmm5
	movaps	xmm5,xmm7				;xmm5 = Matrix[z]
	mulps	xmm4,xmm0				;xmm4 = P0 * Matrix[z]
	movaps	xmm0,TempVectors[00h]	;xmm0 = x0',x1',x2',x3'
	mulps	xmm5,xmm1				;xmm5 = P1 * Matrix[z]
	movaps	xmm1,TempVectors[10h]	;xmm1 = y0',y1',y2',y3'
	mulps	xmm6,xmm2				;xmm6 = P2 * Matrix[z]
	movaps	xmm2,ScreenFactor		;xmm2 = c,c,c,c
	mulps	xmm7,xmm3				;xmm7 = P3 * Matrix[z]
	haddps	xmm4,xmm5
	mulps	xmm0,xmm2				;xmm0 = cx0',cx1',cx2',cx3'
	haddps	xmm6,xmm7
	mulps	xmm1,xmm2				;xmm1 = cy0',cy1',cy2',cy3'
	haddps	xmm4,xmm6				;xmm4 = z0',z1',z2',z3'
	rcpps	xmm4,xmm4				;xmm4 = 1/z0',1/z1',1/z2',1/z3'
	mulps	xmm0,xmm4				;xmm0 = xs0,xs1,xs2,xs3
	mulps	xmm1,xmm4				;xmm1 = ys0,ys1,ys2,ys3
	movaps	xmm5,xmm4				;xmm5 = 1/z0',1/z1',1/z2',1/z3'
	unpcklps	xmm4,xmm4			;xmm4 = 1/z0',1/z0',1/z1',1/z1'
	movaps	xmm2,xmm0				;xmm2 = xs0,xs1,xs2,xs3
	unpckhps	xmm5,xmm5			;xmm5 = 1/z2',1/z2',1/z3',1/z3'
	unpcklps	xmm0,xmm1			;xmm0 = xs0,ys0,xs1,ys1
	unpckhps	xmm2,xmm1			;xmm2 = xs2,ys2,xs3,ys3
	cvtps2dq	xmm0,xmm0			;xmm0 = (int)xs0,(int)ys0,(int)xs1,(int)ys1
	cvtps2dq	xmm2,xmm2			;xmm2 = (int)xs2,(int)ys2,(int)xs3,(int)ys3
	movdqa	[edx][00h],xmm0
	movaps	[edx][10h],xmm4
	movdqa	[edx][20h],xmm2
	movaps	[edx][30h],xmm5
	add		edx,40h
	sub		ecx,4
	ja		NextCubePoint
	ret
TransformPoints	endp

;>*******************************************************************************************************************************
;*																																*
;*	Function:	TransformPointsSlow																								*
;*																																*
;*	Transforms an array of points by a given matrix and then into screen coordinates.  This version does not depend on SSE3.	*
;*																																*
;*	Parameters:																													*
;*	eax	- address of the array of points																						*
;*	ebx	- address of the matrix																									*
;*	ecx	- number of points to transform																							*
;*	edx	- address of destination array																							*
;*																																*
;*	Returns:																													*
;*	eax	- end of the array of input points																						*
;*	edx	- end of the array of output points																						*
;*																																*
;<*******************************************************************************************************************************
TransformPointsSlow	proc
NextCubePoint:
	movaps	xmm0,[eax][00h]			;xmm0 = P0
	movaps	xmm1,[eax][10h]			;xmm1 = P1
	movaps	xmm2,[eax][20h]			;xmm2 = P2
	movaps	xmm3,[eax][30h]			;xmm3 = P3
	add		eax,40h
; Process 4 x's
	movaps	xmm4,[ebx][00h]			;xmm4 = Matrix[x]
	movaps	xmm5,xmm4				;xmm5 = Matrix[x]
	movaps	xmm6,xmm4				;xmm6 = Matrix[x]
	movaps	xmm7,xmm4				;xmm7 = Matrix[x]
	mulps	xmm4,xmm0				;xmm4 = P0 * Matrix[x]
	mulps	xmm5,xmm1				;xmm5 = P1 * Matrix[x]
	mulps	xmm6,xmm2				;xmm6 = P2 * Matrix[x]
	mulps	xmm7,xmm3				;xmm7 = P3 * Matrix[x]
	movaps		TempVectors[20h],xmm4	;tmpA = P0x*Mxx,P0y*Mxy,P0z*Mxz,P0a*Mxa
	unpckhps	xmm4,xmm6				;xmm4 = P0z*Mxz,P2z*Mxz,P0a*Mxa,P2a*Mxa
	movaps		TempVectors[30h],xmm4	;tmpB = P0z*Mxz,P2z*Mxz,P0a*Mxa,P2a*Mxa
	movaps		xmm4,TempVectors[20h]	;xmm4 = P0x*Mxx,P0y*Mxy,P0z*Mxz,P0a*Mxa
	unpcklps	xmm4,xmm6				;xmm4 = P0x*Mxx,P2x*Mxx,P0y*Mxy,P2y*Mxy
	movaps		xmm6,xmm5				;xmm6 = P1x*Mxx,P1y*Mxy,P1z*Mxz,P1a*Mxa
	unpckhps	xmm5,xmm7				;xmm5 = P1z*Mxz,P3z*Mxz,P1a*Mxa,P3a*Mxa
	addps		xmm4,TempVectors[30h]	;xmm4 = P0x*Mxx+P0z*Mxz,P2x*Mxx+P2z*Mxz,P0y*Mxy+P0a*Mxa,P2y*Mxy+P2a*Mxa
	unpcklps	xmm6,xmm7				;xmm6 = P1x*Mxx,P3x*Mxx,P1y*Mxy,P3y*Mxy
	addps		xmm5,xmm6				;xmm5 = P1x*Mxx+P1z*Mxz,P3x*Mxx+P3z*Mxz,P1y*Mxy+P1a*Mxa,P3y*Mxy+P3a*Mxa
	movaps		xmm7,xmm4				;xmm7 = P0x*Mxx+P0z*Mxz,P2x*Mxx+P2z*Mxz,P0y*Mxy+P0a*Mxa,P2y*Mxy+P2a*Mxa
	unpckhps	xmm4,xmm5				;xmm4 = P0y*Mxy+P0a*Mxa,P1y*Mxy+P1a*Mxa,P2y*Mxy+P2a*Mxa,P3y*Mxy+P3a*Mxa
	unpcklps	xmm7,xmm5				;xmm7 = P0x*Mxx+P0z*Mxz,P1x*Mxx+P1z*Mxz,P2x*Mxx+P2z*Mxz,P3x*Mxx+P3z*Mxz
	addps		xmm7,xmm4				;xmm7 = P0.Mx,P1.Mx,P2.Mx,P3.Mx,P4.Mx
										;xmm7 = x0',x1',x2',x3'
	movaps		TempVectors[00h],xmm7

; Process 4 y's
	movaps	xmm4,[ebx][10h]			;xmm4 = Matrix[y]
	movaps	xmm5,xmm4				;xmm5 = Matrix[y]
	movaps	xmm6,xmm4				;xmm6 = Matrix[y]
	movaps	xmm7,xmm4				;xmm7 = Matrix[y]
	mulps	xmm4,xmm0				;xmm4 = P0 * Matrix[y]
	mulps	xmm5,xmm1				;xmm5 = P1 * Matrix[y]
	mulps	xmm6,xmm2				;xmm6 = P2 * Matrix[y]
	mulps	xmm7,xmm3				;xmm7 = P3 * Matrix[y]
	movaps		TempVectors[20h],xmm4	;tmpA = P0x*Myx,P0y*Myy,P0z*Myz,P0a*Mya
	unpckhps	xmm4,xmm6				;xmm4 = P0z*Myz,P2z*Myz,P0a*Mya,P2a*Mya
	movaps		TempVectors[30h],xmm4	;tmpB = P0z*Myz,P2z*Myz,P0a*Mya,P2a*Mya
	movaps		xmm4,TempVectors[20h]	;xmm4 = P0x*Myx,P0y*Myy,P0z*Myz,P0a*Mya
	unpcklps	xmm4,xmm6				;xmm4 = P0x*Myx,P2x*Myx,P0y*Myy,P2y*Myy
	movaps		xmm6,xmm5				;xmm6 = P1x*Myx,P1y*Myy,P1z*Myz,P1a*Mya
	unpckhps	xmm5,xmm7				;xmm5 = P1z*Myz,P3z*Myz,P1a*Mya,P3a*Mya
	addps		xmm4,TempVectors[30h]	;xmm4 = P0x*Myx+P0z*Myz,P2x*Myx+P2z*Myz,P0y*Myy+P0a*Mya,P2y*Myy+P2a*Mya
	unpcklps	xmm6,xmm7				;xmm6 = P1x*Myx,P3x*Myx,P1y*Myy,P3y*Myy
	addps		xmm5,xmm6				;xmm5 = P1x*Myx+P1z*Myz,P3x*Myx+P3z*Myz,P1y*Myy+P1a*Mya,P3y*Myy+P3a*Mya
	movaps		xmm7,xmm4				;xmm7 = P0x*Myx+P0z*Myz,P2x*Myx+P2z*Myz,P0y*Myy+P0a*Mya,P2y*Myy+P2a*Mya
	unpckhps	xmm4,xmm5				;xmm4 = P0y*Myy+P0a*Mya,P1y*Myy+P1a*Mya,P2y*Myy+P2a*Mya,P3y*Myy+P3a*Mya
	unpcklps	xmm7,xmm5				;xmm7 = P0x*Myx+P0z*Myz,P1x*Myx+P1z*Myz,P2x*Myx+P2z*Myz,P3x*Myx+P3z*Myz
	addps		xmm7,xmm4				;xmm7 = P0.My,P1.My,P2.My,P3.My,P4.My
										;xmm7 = y0',y1',y2',y3'
	movaps		TempVectors[10h],xmm7

; Process 4 z's
	movaps	xmm4,[ebx][20h]			;xmm4 = Matrix[z]
	movaps	xmm5,xmm4				;xmm5 = Matrix[z]
	movaps	xmm6,xmm4				;xmm6 = Matrix[z]
	movaps	xmm7,xmm4				;xmm7 = Matrix[z]
	mulps	xmm4,xmm0				;xmm4 = P0 * Matrix[z]
	mulps	xmm5,xmm1				;xmm5 = P1 * Matrix[z]
	mulps	xmm6,xmm2				;xmm6 = P2 * Matrix[z]
	mulps	xmm7,xmm3				;xmm7 = P3 * Matrix[z]
	movaps		TempVectors[20h],xmm4	;tmpA = P0x*Mzx,P0y*Mzy,P0z*Mzz,P0a*Mza
	unpckhps	xmm4,xmm6				;xmm4 = P0z*Mzz,P2z*Mzz,P0a*Mza,P2a*Mza
	movaps		TempVectors[30h],xmm4	;tmpB = P0z*Mzz,P2z*Mzz,P0a*Mza,P2a*Mza
	movaps		xmm4,TempVectors[20h]	;xmm4 = P0x*Mzx,P0y*Mzy,P0z*Mzz,P0a*Mza
	unpcklps	xmm4,xmm6				;xmm4 = P0x*Mzx,P2x*Mzx,P0y*Mzy,P2y*Mzy
	movaps		xmm6,xmm5				;xmm6 = P1x*Mzx,P1y*Mzy,P1z*Mzz,P1a*Mza
	unpckhps	xmm5,xmm7				;xmm5 = P1z*Mzz,P3z*Mzz,P1a*Mza,P3a*Mza
	addps		xmm4,TempVectors[30h]	;xmm4 = P0x*Mzx+P0z*Mzz,P2x*Mzx+P2z*Mzz,P0y*Mzy+P0a*Mza,P2y*Mzy+P2a*Mza
	unpcklps	xmm6,xmm7				;xmm6 = P1x*Mzx,P3x*Mzx,P1y*Mzy,P3y*Mzy
	addps		xmm5,xmm6				;xmm5 = P1x*Mzx+P1z*Mzz,P3x*Mzx+P3z*Mzz,P1y*Mzy+P1a*Mza,P3y*Mzy+P3a*Mza
	movaps		xmm7,xmm4				;xmm7 = P0x*Mzx+P0z*Mzz,P2x*Mzx+P2z*Mzz,P0y*Mzy+P0a*Mza,P2y*Mzy+P2a*Mza
	unpckhps	xmm4,xmm5				;xmm4 = P0y*Mzy+P0a*Mza,P1y*Mzy+P1a*Mza,P2y*Mzy+P2a*Mza,P3y*Mzy+P3a*Mza
	unpcklps	xmm7,xmm5				;xmm7 = P0x*Mzx+P0z*Mzz,P1x*Mzx+P1z*Mzz,P2x*Mzx+P2z*Mzz,P3x*Mzx+P3z*Mzz
	addps		xmm7,xmm4				;xmm7 = P0.Mz,P1.Mz,P2.Mz,P3.Mz,P4.Mz
										;xmm7 = z0',z1',z2',z3'

	movaps		xmm0,TempVectors[00h]	;xmm0 = x0',x1',x2',x3'
	movaps		xmm1,TempVectors[10h]	;xmm1 = y0',y1',y2',y3'
	movaps		xmm2,ScreenFactor		;xmm2 = c,c,c,c
	mulps		xmm0,xmm2				;xmm0 = cx0',cx1',cx2',cx3'
	mulps		xmm1,xmm2				;xmm1 = cy0',cy1',cy2',cy3'
	rcpps		xmm7,xmm7				;xmm7 = 1/z0',1/z1',1/z2',1/z3'
	mulps		xmm0,xmm7				;xmm0 = xs0,xs1,xs2,xs3
	mulps		xmm1,xmm7				;xmm1 = ys0,ys1,ys2,ys3
	movaps		xmm5,xmm7				;xmm5 = 1/z0',1/z1',1/z2',1/z3'
	unpcklps	xmm7,xmm7				;xmm7 = 1/z0',1/z0',1/z1',1/z1'
	movaps		xmm2,xmm0				;xmm2 = xs0,xs1,xs2,xs3
	unpckhps	xmm5,xmm5			;xmm5 = 1/z2',1/z2',1/z3',1/z3'
	unpcklps	xmm0,xmm1			;xmm0 = xs0,ys0,xs1,ys1
	unpckhps	xmm2,xmm1			;xmm2 = xs2,ys2,xs3,ys3
	cvtps2dq	xmm0,xmm0			;xmm0 = (int)xs0,(int)ys0,(int)xs1,(int)ys1
	cvtps2dq	xmm2,xmm2			;xmm2 = (int)xs2,(int)ys2,(int)xs3,(int)ys3
	movdqa		[edx][00h],xmm0
	movaps		[edx][10h],xmm7
	movdqa		[edx][20h],xmm2
	movaps		[edx][30h],xmm5
	add			edx,40h
	sub			ecx,4
	ja			NextCubePoint
	ret
TransformPointsSlow	endp

;>*******************************************************************************************************************************
;*																																*
;*	Function:	UpdateObjects																									*
;*																																*
;*	This function moves the view point and adjusts its direction.																*
;*																																*
;<*******************************************************************************************************************************
UpdateObjects	proc
	movaps	xmm0,ViewPosition		;xmm0 = p
	movaps	xmm6,ViewVelocity		;xmm6 = v
	addps	xmm0,xmm6				;xmm0 = new p
	movaps	ViewPosition,xmm0
	movss	xmm7,ViewEnergy			;xmm7 = E_tot
	cmp		isSSE3Supported,TRUE
	jne		UpdateViewWithNoSSE3
	call	CalculateVelocity		;Returns new velocity in xmm6
	movaps	ViewVelocity,xmm6
	movaps	xmm0,ViewPosition
	call	LookAtOrigin
	jmp		DoneUpdateView
UpdateViewWithNoSSE3:
	call	CalculateVelocitySlow	;Returns new velocity in xmm6
	movaps	ViewVelocity,xmm6
	movaps	xmm0,ViewPosition
	call	LookAtOriginSlow
DoneUpdateView:

	movaps	xmm0,OrbitAPosition		;xmm0 = p
	movaps	xmm6,OrbitAVelocity		;xmm6 = v
	addps	xmm0,xmm6				;xmm0 = new p
	movaps	OrbitAPosition,xmm0
	movss	xmm7,OrbitAEnergy		;xmm7 = E_tot
	cmp		isSSE3Supported,TRUE
	jne		UpdateOrbitAWithNoSSE3
	call	CalculateVelocity		;Returns new velocity in xmm6
	movaps	OrbitAVelocity,xmm6
	movaps	xmm0,OrbitAPosition
	mov		eax,offset OrbitARight
	mov		edx,offset ViewInverseOrbitA
	call	InverseLookAtOrigin
	jmp		DoneUpdateOrbitA
UpdateOrbitAWithNoSSE3:
	call	CalculateVelocitySlow	;Returns new velocity in xmm6
	movaps	OrbitAVelocity,xmm6
	movaps	xmm0,OrbitAPosition
	mov		eax,offset OrbitARight
	mov		edx,offset ViewInverseOrbitA
	call	InverseLookAtOriginSlow
DoneUpdateOrbitA:

	movaps	xmm0,OrbitBPosition		;xmm0 = p
	movaps	xmm6,OrbitBVelocity		;xmm6 = v
	addps	xmm0,xmm6				;xmm0 = new p
	movaps	OrbitBPosition,xmm0
	movss	xmm7,OrbitBEnergy		;xmm7 = E_tot
	cmp		isSSE3Supported,TRUE
	jne		UpdateOrbitBWithNoSSE3
	call	CalculateVelocity		;Returns new velocity in xmm6
	movaps	OrbitBVelocity,xmm6
	movaps	xmm0,OrbitBPosition
	mov		eax,offset OrbitBRight
	mov		edx,offset ViewInverseOrbitB
	call	InverseLookAtOrigin
	jmp		DoneUpdateOrbitB
UpdateOrbitBWithNoSSE3:
	call	CalculateVelocitySlow	;Returns new velocity in xmm6
	movaps	OrbitBVelocity,xmm6
	movaps	xmm0,OrbitBPosition
	mov		eax,offset OrbitBRight
	mov		edx,offset ViewInverseOrbitB
	call	InverseLookAtOriginSlow
DoneUpdateOrbitB:

;Move forward the glowing neuron numbers.
	push	ebx
	mov		ecx,GlowIndices[0]
	shl		ecx,2
	lea		ecx,NeuronGraph[ecx*2+ecx]
	mov		edx,[ecx]
	mov		ebx,[ecx][4]
	mov		ecx,[ecx][8]
	cmp		edx,GlowIndices[4]
	cmove	edx,ecx
	cmp		ebx,GlowIndices[4]
	cmove	ebx,ecx
	cmp		edx,-1
	cmove	edx,ebx
	je		SingleOption
	cmp		ebx,-1
	je		SingleOption
	push	edx
	invoke	GetRandomNumber,pRenderRandom
	pop		edx
	test	eax,1
	cmovnz	edx,ebx
SingleOption:
	xchg	GlowIndices[0],edx
	xchg	GlowIndices[4],edx
	xchg	GlowIndices[8],edx
	xchg	GlowIndices[12],edx
	xchg	GlowIndices[16],edx
	mov		GlowIndices[20],edx
	pop		ebx

	add		GlowSizeIndex,1
	and		GlowSizeIndex,0Fh

;Move CurrentQ and CurrentR one step closer to GoalQ and GoalR
	movss	xmm0,GoalQ
	movss	xmm1,GoalR
	subss	xmm0,CurrentQ			;xmm0 = dQ
	subss	xmm1,CurrentR			;xmm1 = dR
	movss	xmm2,xmm0				;xmm2 = dQ
	movss	xmm3,xmm0				;xmm3 = dQ
	movss	xmm4,xmm1				;xmm4 = dR
	mulss	xmm0,xmm0				;xmm0 = dQdQ
	mulss	xmm2,xmm1				;xmm2 = dQdR
	mulss	xmm1,xmm1				;xmm1 = dRdR
	addss	xmm0,xmm2				;xmm0 = dQdQ+dQdR+dRdR
	rsqrtss	xmm0,xmm0				;xmm0 = 1/sqrt(dQdQ+dQdR+dRdR) = 1/distance in the standard basis instead of the Q,R basis
	movd	eax,xmm0
	and		eax,7F800000h
	cmp		eax,7F800000h			;If the 1/distance to the goal is NaN or infinity,
	je		AdjustForNaNOrInfinity	;change the goal.
	comiss	xmm0,RecipQRSDistanceStep
	jb		DidntReachGoalQR
	mov		eax,GoalQ
	mov		ecx,GoalR
	mov		CurrentQ,eax
	mov		CurrentR,ecx
AdjustForNaNOrInfinity:
	invoke	GetRandomFloat,pRenderRandom
	movss	xmm1,xmm0				;xmm1 = new GoalR
	invoke	GetRandomFloat,pRenderRandom
	movss	xmm2,xmm0				;xmm2 = xmm0 = new GoalQ
	addss	xmm2,xmm1				;xmm2 = new GoalQ + new GoalR
	comiss	xmm2,AllOne.x			;S=1-Q-R, so to ensure S>=0, it must be that Q+R<=1
	jbe		SIsNotNegative
	subss	xmm0,AllOne.x			;To do the rotation adjustment, simply do
	subss	xmm1,AllOne.x			;Q = 1-Q
	mulss	xmm0,AllNegativeOne.x	;R = 1-R
	mulss	xmm1,AllNegativeOne.x	;
SIsNotNegative:
	movss	GoalQ,xmm0
	movss	GoalR,xmm1
	jmp		DoneUpdateQR
DidntReachGoalQR:
	mulss	xmm0,QRSDistanceStep	;xmm0 = D/|QR|
	mulss	xmm3,xmm0				;xmm3 = D*dQ/|QR| = dQ'
	mulss	xmm4,xmm0				;xmm4 = D*dR/|QR| = dR'
	addss	xmm3,CurrentQ			;xmm3 = Q+dQ' = new Q
	addss	xmm4,CurrentR			;xmm4 = R+dR' = new R
	movss	CurrentQ,xmm3
	movss	CurrentR,xmm4
DoneUpdateQR:

	ret
UpdateObjects	endp

;>*******************************************************************************************************************************
;*																																*
;*	Function:	LookAtOrigin																									*
;*																																*
;*	This function takes the position and orientation of the view, and makes <ViewInverse> out of it, aligning one axis to		*
;*	always face the origin.																										*
;*																																*
;*	Parameters:																													*
;*	xmm0	- This is the position of the view.																					*
;*																																*
;<*******************************************************************************************************************************
LookAtOrigin	proc
	movaps	xmm2,xmm0			;xmm2 = p
	movaps	xmm7,xmm0			;xmm7 = p
	mulps	xmm0,xmm0			;xmm0 = p.p,p.p,p.p,p.p
	haddps	xmm0,xmm0			;
	haddps	xmm0,xmm0			;
	rsqrtps	xmm3,xmm0			;xmm3 = 1/|p|,1/|p|,1/|p|,1/|p|
	rcpps	xmm0,xmm0			;xmm0 = 1/|p|^2,1/|p|^2,1/|p|^2,1/|p|^2
	mulps	xmm7,xmm3			;xmm7 = p/|p| = b
	mulps	xmm0,xmm2			;xmm0 = p/|p|^2
	movaps	xmm5,xmm0			;xmm5 = p/|p|^2
	movaps	xmm3,xmm2			;xmm3 = p
	movaps	ViewInverse[20h],xmm7
	movaps	xmm6,ViewRight		;xmm6 = r
	mulps	xmm3,AllNegativeOne	;xmm3 = -p
	mulps	xmm2,xmm6			;xmm2 = r.p,r.p,r.p,r.p
	haddps	xmm2,xmm2			;
	haddps	xmm2,xmm2			;
	movaps	xmm0,xmm3			;xmm0 = -p
	movaps	xmm1,xmm3			;xmm1 = -p
	mulps	xmm3,xmm7			;xmm3 = -bx*px,-by*py,-bz*pz,0
	mulps	xmm2,xmm5			;xmm2 = (r.p/p.p)p = projection of r onto p
	subps	xmm6,xmm2			;xmm6 = new r = r-(r.p/p.p)p = projection of r onto plane with normal p = closest vector to r that is perpendicular to p
	movaps	xmm7,xmm6			;xmm7 = r
	mulps	xmm6,xmm6			;xmm6 = r.r,r.r,r.r,r.r
	haddps	xmm6,xmm6			;
	haddps	xmm6,xmm6			;
	rsqrtps	xmm6,xmm6			;xmm6 = 1/|r|,1/|r|,1/|r|,1/|r|
	mulps	xmm6,xmm7			;xmm6 = real new r = r/|r|
	movaps	ViewRight,xmm6
	movaps	ViewInverse[00h],xmm6

	mulps	xmm0,xmm6			;xmm0 = -rx*px,-ry*py,-rz*pz,0

	movaps	xmm7,xmm6			;xmm7 = r
	shufps	xmm6,xmm6,11001001b	;xmm6 = ry,rz,rx,--
	shufps	xmm7,xmm7,11010010b	;xmm7 = rz,rx,ry,--
	mulps	xmm6,xmm5			;xmm6 = c(px*ry,py*rz,pz*rx,--)
	mulps	xmm7,xmm5			;xmm7 = c(px*rz,py*rx,pz*ry,--)
	shufps	xmm6,xmm6,11001001b	;xmm6 = c(py*rz,pz*rx,px*ry,--)
	shufps	xmm7,xmm7,11010010b	;xmm7 = c(pz*ry,px*rz,py*rx,--)
	subps	xmm6,xmm7			;xmm6 = u = p X r
	movaps	xmm7,xmm6			;xmm7 = u
	mulps	xmm6,xmm6			;xmm6 = u.u,u.u,u.u,u.u
	haddps	xmm6,xmm6			;
	haddps	xmm6,xmm6			;
	rsqrtps	xmm6,xmm6			;xmm6 = 1/|u|,1/|u|,1/|u|,1/|u|
	mulps	xmm6,xmm7			;xmm6 = real u = u/|u|
	movaps	ViewInverse[10h],xmm6

	mulps	xmm1,xmm6			;xmm1 = -ux*px,-uy*py,-uz*pz,0

	haddps	xmm0,xmm1			;xmm0 = -rx*px-ry*py,-rz*pz,-ux*px-uy*py,-uz*pz
	haddps	xmm3,xmm3			;xmm3 = -bx*px-by*py,-bz*pz,-bx*px-by*py,-bz*pz
	haddps	xmm0,xmm3			;xmm0 = -r.p,-u.p,-b.p,-b.p
	movaps	TempVectors[00h],xmm0


	mov		eax,dword ptr TempVectors[00h]
	mov		ecx,dword ptr TempVectors[04h]
	mov		edx,dword ptr TempVectors[08h]
	mov		dword ptr ViewInverse[00h].a,eax
	mov		dword ptr ViewInverse[10h].a,ecx
	mov		dword ptr ViewInverse[20h].a,edx
	ret
LookAtOrigin	endp

;>*******************************************************************************************************************************
;*																																*
;*	Function:	LookAtOriginSlow																								*
;*																																*
;*	This function takes the position and orientation of the view, and makes <ViewInverse> out of it, aligning one axis to		*
;*	always face the origin.																										*
;*																																*
;*	Parameters:																													*
;*	xmm0	- This is the position of the view.																					*
;*																																*
;<*******************************************************************************************************************************
LookAtOriginSlow	proc
	movaps	xmm2,xmm0			;xmm2 = p
	movaps	xmm7,xmm0			;xmm7 = p
	mulps	xmm0,xmm0			;xmm0 = p.p,p.p,p.p,p.p
	movhlps	xmm1,xmm0			;
	addps	xmm0,xmm1			;
	movss	xmm1,xmm0			;
	shufps	xmm0,xmm0,01b		;
	addss	xmm0,xmm1			;
	shufps	xmm0,xmm0,00000000b	;
	rsqrtps	xmm3,xmm0			;xmm3 = 1/|p|,1/|p|,1/|p|,1/|p|
	rcpps	xmm0,xmm0			;xmm0 = 1/|p|^2,1/|p|^2,1/|p|^2,1/|p|^2
	mulps	xmm7,xmm3			;xmm7 = p/|p| = b
	mulps	xmm0,xmm2			;xmm0 = p/|p|^2
	movaps	xmm5,xmm0			;xmm5 = p/|p|^2
	movaps	xmm3,xmm2			;xmm3 = p
	movaps	ViewInverse[20h],xmm7
	movaps	xmm6,ViewRight		;xmm6 = r
	mulps	xmm3,AllNegativeOne	;xmm3 = -p
	mulps	xmm2,xmm6			;xmm2 = r.p,r.p,r.p,r.p
	movhlps	xmm1,xmm2			;
	addps	xmm2,xmm1			;
	movss	xmm1,xmm2			;
	shufps	xmm2,xmm2,01b		;
	addss	xmm2,xmm1			;
	shufps	xmm2,xmm2,00000000b	;
	movaps	xmm0,xmm3			;xmm0 = -p
	movaps	xmm1,xmm3			;xmm1 = -p
	mulps	xmm3,xmm7			;xmm3 = -bx*px,-by*py,-bz*pz,0
	mulps	xmm2,xmm5			;xmm2 = (r.p/p.p)p = projection of r onto p
	subps	xmm6,xmm2			;xmm6 = new r = r-(r.p/p.p)p = projection of r onto plane with normal p = closest vector to r that is perpendicular to p
	movaps	xmm7,xmm6			;xmm7 = r
	mulps	xmm6,xmm6			;xmm6 = r.r,r.r,r.r,r.r
	movhlps	xmm2,xmm6			;
	addps	xmm6,xmm2			;
	movss	xmm2,xmm6			;
	shufps	xmm6,xmm6,01b		;
	addss	xmm6,xmm2			;
	shufps	xmm6,xmm6,00000000b	;
	rsqrtps	xmm6,xmm6			;xmm6 = 1/|r|,1/|r|,1/|r|,1/|r|
	mulps	xmm6,xmm7			;xmm6 = real new r = r/|r|
	movaps	ViewRight,xmm6
	movaps	ViewInverse[00h],xmm6

	mulps	xmm0,xmm6			;xmm0 = -rx*px,-ry*py,-rz*pz,0

	movaps	xmm7,xmm6			;xmm7 = r
	shufps	xmm6,xmm6,11001001b	;xmm6 = ry,rz,rx,--
	shufps	xmm7,xmm7,11010010b	;xmm7 = rz,rx,ry,--
	mulps	xmm6,xmm5			;xmm6 = c(px*ry,py*rz,pz*rx,--)
	mulps	xmm7,xmm5			;xmm7 = c(px*rz,py*rx,pz*ry,--)
	shufps	xmm6,xmm6,11001001b	;xmm6 = c(py*rz,pz*rx,px*ry,--)
	shufps	xmm7,xmm7,11010010b	;xmm7 = c(pz*ry,px*rz,py*rx,--)
	subps	xmm6,xmm7			;xmm6 = u = p X r
	movaps	xmm7,xmm6			;xmm7 = u
	mulps	xmm6,xmm6			;xmm6 = u.u,u.u,u.u,u.u
	movhlps	xmm2,xmm6			;
	addps	xmm6,xmm2			;
	movss	xmm2,xmm6			;
	shufps	xmm6,xmm6,01b		;
	addss	xmm6,xmm2			;
	shufps	xmm6,xmm6,00000000b	;
	rsqrtps	xmm6,xmm6			;xmm6 = 1/|u|,1/|u|,1/|u|,1/|u|
	mulps	xmm6,xmm7			;xmm6 = real u = u/|u|
	movaps	ViewInverse[10h],xmm6

	mulps	xmm1,xmm6			;xmm1 = -ux*px,-uy*py,-uz*pz,0

	movaps		xmm4,xmm3				;xmm4 = -bx*px,-by*py,-bz*pz,0
	movaps		xmm2,xmm0				;xmm2 = -rx*px,-ry*py,-rz*pz,0
	unpcklps	xmm0,xmm1				;xmm0 = -rx*px,-ux*px,-ry*py,-uy*py
	movhlps		xmm1,xmm0				;xmm1 = -ry*py,-uy*py,-uz*pz,0
	unpckhps	xmm2,xmm1				;xmm2 = -rz*pz,-uz*pz,0,0
	unpcklps	xmm3,xmm3				;xmm3 = -bx*px,-bx*px,-by*py,-by*py
	movlhps		xmm0,xmm3				;xmm0 = -rx*px,-ux*px,-bx*px,-bx*px
	movhlps		xmm3,xmm3				;xmm3 = -by*py,-by*py,-by*py,-by*py
	movlhps		xmm1,xmm3				;xmm1 = -ry*py,-uy*py,-by*py,-by*py
	addps		xmm0,xmm1				;xmm0 = -rx*px-ry*py,-ux*px-uy*py,-bx*px-by*py,-bx*px-by*py
	movhlps		xmm4,xmm4				;xmm4 = -bz*pz,0,-bz*pz,0
	movlhps		xmm2,xmm4				;xmm2 = -rz*pz,-uz*pz,-bz*pz,0
	addps		xmm0,xmm2				;xmm0 = -r.p,-u.p,-b.p,----

	movaps	TempVectors[00h],xmm0


	mov		eax,dword ptr TempVectors[00h].x
	mov		ecx,dword ptr TempVectors[00h].y
	mov		edx,dword ptr TempVectors[00h].z
	mov		dword ptr ViewInverse[00h].a,eax
	mov		dword ptr ViewInverse[10h].a,ecx
	mov		dword ptr ViewInverse[20h].a,edx
	ret
LookAtOriginSlow	endp

;>*******************************************************************************************************************************
;*																																*
;*	Function:	InverseLookAtOrigin																								*
;*																																*
;*	This function takes the position and orientation of an object, and makes a matrix out of it aligning one axis to always		*
;*	face the origin.																											*
;*																																*
;*	Parameters:																													*
;*	xmm0	- This is the position of the object.																				*
;*	eax		- This is the address of the right vector of the object (not yet updated).											*
;*	edx		- This is the address of the resulting matrix.																		*
;*																																*
;<*******************************************************************************************************************************
InverseLookAtOrigin	proc
;First, find the normalized position (the back vector)
	movaps	xmm2,xmm0				;xmm2 = p
	movaps	xmm7,xmm0				;xmm7 = p
	mulps	xmm0,xmm0				;xmm0 = p.p,p.p,p.p,p.p
	haddps	xmm0,xmm0				;
	haddps	xmm0,xmm0				;
	rsqrtps	xmm3,xmm0				;xmm3 = 1/|p|,1/|p|,1/|p|,1/|p|
	rcpps	xmm0,xmm0				;xmm0 = 1/|p|^2,1/|p|^2,1/|p|^2,1/|p|^2
	mulps	xmm7,xmm3				;xmm7 = p/|p| = b
	mulps	xmm0,xmm2				;xmm0 = p/|p|^2
	movaps	xmm3,xmm2				;xmm3 = p
;and calculate its corresponding matrix column
	movaps	xmm1,ViewInverse[00h]	;xmm1 = R,--
	movaps	xmm4,ViewInverse[10h]	;xmm4 = U,--
	movaps	xmm5,ViewInverse[20h]	;xmm5 = B,--
	xorps	xmm6,xmm6				;xmm6 = 0
	mulps	xmm1,xmm7				;xmm1 = Rx*bx,Ry*by,Rz*bz,0
	mulps	xmm4,xmm7				;xmm4 = Ux*bx,Uy*by,Uz*bz,0
	mulps	xmm5,xmm7				;xmm5 = Bx*bx,By*by,Bz*bz,0
	haddps	xmm1,xmm4				;xmm1 = R.b,U.b,B.b,0
	haddps	xmm5,xmm6				;
	haddps	xmm1,xmm5				;
	movaps	[edx][20h],xmm1
;Second, update the right vector
	movaps	xmm6,[eax]				;xmm6 = r
	mulps	xmm2,xmm6				;xmm2 = r.p,r.p,r.p,r.p
	haddps	xmm2,xmm2				;
	haddps	xmm2,xmm2				;
	mulps	xmm2,xmm0				;xmm2 = (r.p/p.p)p = projection of r onto p
	subps	xmm6,xmm2				;xmm6 = new r = r-(r.p/p.p)p = projection of r onto plane with normal p = closest vector to r that is perpendicular to p
	movaps	xmm0,xmm6				;xmm0 = r
	mulps	xmm6,xmm6				;xmm6 = r.r,r.r,r.r,r.r
	haddps	xmm6,xmm6				;
	haddps	xmm6,xmm6				;
	rsqrtps	xmm6,xmm6				;xmm6 = 1/|r|,1/|r|,1/|r|,1/|r|
	mulps	xmm6,xmm0				;xmm6 = real new r = r/|r|
	movaps	[eax],xmm6
;and calculate its corresponding matrix column
	movaps	xmm1,ViewInverse[00h]	;xmm1 = R,--
	movaps	xmm4,ViewInverse[10h]	;xmm4 = U,--
	movaps	xmm5,ViewInverse[20h]	;xmm5 = B,--
	xorps	xmm0,xmm0				;xmm0 = 0
	mulps	xmm1,xmm6				;xmm1 = Rx*rx,Ry*ry,Rz*rz,0
	mulps	xmm4,xmm6				;xmm4 = Ux*rx,Uy*ry,Uz*rz,0
	mulps	xmm5,xmm6				;xmm5 = Bx*rx,By*ry,Bz*rz,0
	haddps	xmm1,xmm4				;xmm1 = R.r,U.r,B.r,0
	haddps	xmm5,xmm0				;
	haddps	xmm1,xmm5				;
	movaps	[edx][00h],xmm1
;Third, find the up vector (b X r).  Note that xmm7=b, xmm6=r, xmm3=p.
	movaps	xmm1,xmm6				;xmm1 = r
	shufps	xmm6,xmm6,11001001b		;xmm6 = ry,rz,rx,0
	shufps	xmm1,xmm1,11010010b		;xmm1 = rz,rx,ry,0
	mulps	xmm6,xmm7				;xmm6 = bx*ry,by*rz,bz*rx,0
	mulps	xmm1,xmm7				;xmm7 = bx*rz,by*rx,bz*ry,0
	shufps	xmm6,xmm6,11001001b		;xmm6 = by*rz,bz*rx,bx*ry,0
	shufps	xmm1,xmm1,11010010b		;xmm7 = bz*ry,bx*rz,by*rx,0
	subps	xmm6,xmm1				;xmm6 = u = b X r
;and calculate its corresponding matrix column
	movaps	xmm1,ViewInverse[00h]	;xmm1 = R,--
	movaps	xmm4,ViewInverse[10h]	;xmm4 = U,--
	movaps	xmm5,ViewInverse[20h]	;xmm5 = B,--
	xorps	xmm0,xmm0				;xmm0 = 0
	mulps	xmm1,xmm6				;xmm1 = Rx*ux,Ry*uy,Rz*uz,0
	mulps	xmm4,xmm6				;xmm4 = Ux*ux,Uy*uy,Uz*uz,0
	mulps	xmm5,xmm6				;xmm5 = Bx*ux,By*uy,Bz*uz,0
	haddps	xmm1,xmm4				;xmm1 = R.u,U.u,B.u,0
	haddps	xmm5,xmm0				;
	haddps	xmm1,xmm5				;
	movaps	[edx][10h],xmm1
;Fourth, find the position vector
	subps	xmm3,ViewPosition		;xmm3 = p-P
	movaps	xmm4,xmm3				;xmm4 = p-P
	movaps	xmm5,xmm3				;xmm5 = p-P
	mulps	xmm3,ViewInverse[00h]	;xmm3 = Rx*(px-Px),Ry*(py-Py),Rz*(pz-Pz),0
	mulps	xmm4,ViewInverse[10h]	;xmm4 = Ux*(px-Px),Uy*(py-Py),Uz*(pz-Pz),0
	mulps	xmm5,ViewInverse[20h]	;xmm5 = Bx*(px-Px),By*(py-Py),Bz*(pz-Pz),0
	haddps	xmm3,xmm4				;xmm3 = R.(p-P),U.(p-P),B.(p-P),0
	haddps	xmm5,xmm0				;
	haddps	xmm3,xmm5				;
;Last, swizzle the data so that the four vectors are transposed into columns
	movaps		xmm0,[edx][00h]		;xmm0 = R.r,U.r,B.r,0
									;xmm1 = R.u,U.u,B.u,0
	movaps		xmm2,[edx][20h]		;xmm2 = R.b,U.b,B.b,0
									;xmm3 = R.(p-P),U.(p-P),B.(p-P),0

	movaps		xmm4,xmm0			;xmm4 = R.r,U.r,B.r,0
	movaps		xmm5,xmm1			;xmm5 = R.u,U.u,B.u,0
	unpcklps	xmm0,xmm1			;xmm0 = R.r,R.u,U.r,U.u
	movhlps		xmm1,xmm0			;xmm1 = U.r,U.u,B.u,0
	movaps		xmm6,xmm2			;xmm6 = R.b,U.b,B.b,0
	unpcklps	xmm2,xmm3			;xmm2 = R.b,R.(p-P),U.b,U.(p-P)
	movlhps		xmm0,xmm2			;xmm0 = R.r,R.u,R.b,R.(p-P)
	movhlps		xmm2,xmm2			;xmm2 = U.b,U.(p-P),U.b,U.(p-P)
	movlhps		xmm1,xmm2			;xmm1 = U.r,U.u,U.b,U.(p-P)
	movaps		[edx][00h],xmm0
	movaps		[edx][10h],xmm1
	unpckhps	xmm4,xmm6			;xmm4 = B.r,B.b,0,0
	unpckhps	xmm5,xmm3			;xmm5 = B.u,B.(p-P),0,0
	unpcklps	xmm4,xmm5			;xmm4 = B.r,B.u,B.b,B.(p-P)
	movaps		[edx][20h],xmm4

	ret
InverseLookAtOrigin	endp

;>*******************************************************************************************************************************
;*																																*
;*	Function:	InverseLookAtOriginSlow																							*
;*																																*
;*	This function takes the position and orientation of an object, and makes a matrix out of it aligning one axis to always		*
;*	face the origin.																											*
;*																																*
;*	Parameters:																													*
;*	xmm0	- This is the position of the object.																				*
;*	eax		- This is the address of the right vector of the object (not yet updated).											*
;*	edx		- This is the address of the resulting matrix.																		*
;*																																*
;<*******************************************************************************************************************************
InverseLookAtOriginSlow	proc
;First, find the normalized position (the back vector)
	movaps	xmm2,xmm0				;xmm2 = p
	movaps	xmm7,xmm0				;xmm7 = p
	mulps	xmm0,xmm0				;xmm0 = p.p,p.p,p.p,p.p
	movhlps	xmm1,xmm0				;
	addps	xmm0,xmm1				;
	movss	xmm1,xmm0				;
	shufps	xmm0,xmm0,01b			;
	addss	xmm0,xmm1				;
	shufps	xmm0,xmm0,00000000b		;
	rsqrtps	xmm3,xmm0				;xmm3 = 1/|p|,1/|p|,1/|p|,1/|p|
	rcpps	xmm0,xmm0				;xmm0 = 1/|p|^2,1/|p|^2,1/|p|^2,1/|p|^2
	mulps	xmm7,xmm3				;xmm7 = p/|p| = b
	mulps	xmm0,xmm2				;xmm0 = p/|p|^2
	movaps	xmm3,xmm2				;xmm3 = p
;and calculate its corresponding matrix column
	movaps	xmm1,ViewInverse[00h]	;xmm1 = R,--
	movaps	xmm4,ViewInverse[10h]	;xmm4 = U,--
	movaps	xmm5,ViewInverse[20h]	;xmm5 = B,--
	xorps	xmm6,xmm6				;xmm6 = 0
	mulps	xmm1,xmm7				;xmm1 = Rx*bx,Ry*by,Rz*bz,0
	mulps	xmm4,xmm7				;xmm4 = Ux*bx,Uy*by,Uz*bz,0
	mulps	xmm5,xmm7				;xmm5 = Bx*bx,By*by,Bz*bz,0
	
	movaps		TempVectors[20h],xmm1	;tmpA = Rx*bx,Ry*by,Rz*bz,0
	unpckhps	xmm1,xmm5				;xmm1 = Rz*bz,Bz*bz,0,0
	movaps		TempVectors[30h],xmm1	;tmpB = Rz*bz,Bz*bz,0,0
	movaps		xmm1,TempVectors[20h]	;xmm1 = Rx*bx,Ry*by,Rz*bz,0
	unpcklps	xmm1,xmm5				;xmm1 = Rx*bx,Bx*bx,Ry*by,By*by
	movaps		xmm5,xmm4				;xmm5 = Ux*bx,Uy*by,Uz*bz,0
	unpckhps	xmm4,xmm6				;xmm4 = Uz*bz,0,0,0
	addps		xmm1,TempVectors[30h]	;xmm1 = Rx*bx+Rz*bz,Bx*bx+Bz*bz,Ry*by,By*by
	unpcklps	xmm5,xmm6				;xmm5 = Ux*bx,0,Uy*by,0
	addps		xmm4,xmm5				;xmm4 = Ux*bx+Uz*bz,0,Uy*by,0
	movaps		xmm6,xmm1				;xmm6 = Rx*bx+Rz*bz,Bx*bx+Bz*bz,Ry*by,By*by
	unpckhps	xmm1,xmm4				;xmm1 = Ry*by,Uy*by,By*by,0
	unpcklps	xmm6,xmm4				;xmm6 = Rx*bx+Rz*bz,Ux*bx+Uz*bz,Bx*bx+Bz*bz,0
	addps		xmm1,xmm6				;xmm1 = Rx*bx+Ry*by+Rz*bz,Ux*bx+Uy*by+Uz*bz,Bx*bx+By*by+Bz*bz,0
										;xmm1 = R.b,U.b,B.b,0
	movaps	[edx][20h],xmm1
;Second, update the right vector
	movaps	xmm6,[eax]				;xmm6 = r
	mulps	xmm2,xmm6				;xmm2 = r.p,r.p,r.p,r.p
	movhlps	xmm1,xmm2				;
	addps	xmm2,xmm1				;
	movss	xmm1,xmm2				;
	shufps	xmm2,xmm2,01b			;
	addss	xmm2,xmm1				;
	shufps	xmm2,xmm2,00000000b		;
	mulps	xmm2,xmm0				;xmm2 = (r.p/p.p)p = projection of r onto p
	subps	xmm6,xmm2				;xmm6 = new r = r-(r.p/p.p)p = projection of r onto plane with normal p = closest vector to r that is perpendicular to p
	movaps	xmm0,xmm6				;xmm0 = r
	mulps	xmm6,xmm6				;xmm6 = r.r,r.r,r.r,r.r
	movhlps	xmm1,xmm6				;
	addps	xmm6,xmm1				;
	movss	xmm1,xmm6				;
	shufps	xmm6,xmm6,01b			;
	addss	xmm6,xmm1				;
	shufps	xmm6,xmm6,00000000b		;
	rsqrtps	xmm6,xmm6				;xmm6 = 1/|r|,1/|r|,1/|r|,1/|r|
	mulps	xmm6,xmm0				;xmm6 = real new r = r/|r|
	movaps	[eax],xmm6
;and calculate its corresponding matrix column
	movaps	xmm1,ViewInverse[00h]	;xmm1 = R,--
	movaps	xmm4,ViewInverse[10h]	;xmm4 = U,--
	movaps	xmm5,ViewInverse[20h]	;xmm5 = B,--
	xorps	xmm0,xmm0				;xmm0 = 0
	mulps	xmm1,xmm6				;xmm1 = Rx*rx,Ry*ry,Rz*rz,0
	mulps	xmm4,xmm6				;xmm4 = Ux*rx,Uy*ry,Uz*rz,0
	mulps	xmm5,xmm6				;xmm5 = Bx*rx,By*ry,Bz*rz,0

	movaps		TempVectors[20h],xmm1	;tmpA = Rx*rx,Ry*ry,Rz*rz,0
	unpckhps	xmm1,xmm5				;xmm1 = Rz*rz,Bz*rz,0,0
	movaps		TempVectors[30h],xmm1	;tmpB = Rz*rz,Bz*rz,0,0
	movaps		xmm1,TempVectors[20h]	;xmm1 = Rx*rx,Ry*ry,Rz*rz,0
	unpcklps	xmm1,xmm5				;xmm1 = Rx*rx,Bx*rx,Ry*ry,By*ry
	movaps		xmm5,xmm4				;xmm5 = Ux*rx,Uy*ry,Uz*rz,0
	unpckhps	xmm4,xmm0				;xmm4 = Uz*rz,0,0,0
	addps		xmm1,TempVectors[30h]	;xmm1 = Rx*rx+Rz*rz,Bx*rx+Bz*rz,Ry*ry,By*ry
	unpcklps	xmm5,xmm0				;xmm5 = Ux*rx,0,Uy*ry,0
	addps		xmm4,xmm5				;xmm4 = Ux*rx+Uz*rz,0,Uy*ry,0
	movaps		xmm0,xmm1				;xmm0 = Rx*rx+Rz*rz,Bx*rx+Bz*rz,Ry*ry,By*ry
	unpckhps	xmm1,xmm4				;xmm1 = Ry*ry,Uy*ry,By*ry,0
	unpcklps	xmm0,xmm4				;xmm0 = Rx*rx+Rz*rz,Ux*rx+Uz*rz,Bx*rx+Bz*rz,0
	addps		xmm1,xmm0				;xmm1 = Rx*rx+Ry*ry+Rz*rz,Ux*rx+Uy*ry+Uz*rz,Bx*rx+By*ry+Bz*rz,0
										;xmm1 = R.r,U.r,B.r,0
	movaps	[edx][00h],xmm1
;Third, find the up vector (b X r).  Note that xmm7=b, xmm6=r, xmm3=p.
	movaps	xmm1,xmm6				;xmm1 = r
	shufps	xmm6,xmm6,11001001b		;xmm6 = ry,rz,rx,0
	shufps	xmm1,xmm1,11010010b		;xmm1 = rz,rx,ry,0
	mulps	xmm6,xmm7				;xmm6 = bx*ry,by*rz,bz*rx,0
	mulps	xmm1,xmm7				;xmm7 = bx*rz,by*rx,bz*ry,0
	shufps	xmm6,xmm6,11001001b		;xmm6 = by*rz,bz*rx,bx*ry,0
	shufps	xmm1,xmm1,11010010b		;xmm7 = bz*ry,bx*rz,by*rx,0
	subps	xmm6,xmm1				;xmm6 = u = b X r
;and calculate its corresponding matrix column
	movaps	xmm1,ViewInverse[00h]	;xmm1 = R,--
	movaps	xmm4,ViewInverse[10h]	;xmm4 = U,--
	movaps	xmm5,ViewInverse[20h]	;xmm5 = B,--
	xorps	xmm0,xmm0				;xmm0 = 0
	mulps	xmm1,xmm6				;xmm1 = Rx*ux,Ry*uy,Rz*uz,0
	mulps	xmm4,xmm6				;xmm4 = Ux*ux,Uy*uy,Uz*uz,0
	mulps	xmm5,xmm6				;xmm5 = Bx*ux,By*uy,Bz*uz,0

	movaps		TempVectors[20h],xmm1	;tmpA = Rx*ux,Ry*uy,Rz*uz,0
	unpckhps	xmm1,xmm5				;xmm1 = Rz*uz,Bz*uz,0,0
	movaps		TempVectors[30h],xmm1	;tmpB = Rz*uz,Bz*uz,0,0
	movaps		xmm1,TempVectors[20h]	;xmm1 = Rx*ux,Ry*uy,Rz*uz,0
	unpcklps	xmm1,xmm5				;xmm1 = Rx*ux,Bx*ux,Ry*uy,By*uy
	movaps		xmm5,xmm4				;xmm5 = Ux*ux,Uy*uy,Uz*uz,0
	unpckhps	xmm4,xmm0				;xmm4 = Uz*uz,0,0,0
	addps		xmm1,TempVectors[30h]	;xmm1 = Rx*ux+Rz*uz,Bx*ux+Bz*uz,Ry*uy,By*uy
	unpcklps	xmm5,xmm0				;xmm5 = Ux*ux,0,Uy*uy,0
	addps		xmm4,xmm5				;xmm4 = Ux*ux+Uz*uz,0,Uy*uy,0
	movaps		xmm0,xmm1				;xmm0 = Rx*ux+Rz*uz,Bx*ux+Bz*uz,Ry*uy,By*uy
	unpckhps	xmm1,xmm4				;xmm1 = Ry*uy,Uy*uy,By*uy,0
	unpcklps	xmm0,xmm4				;xmm0 = Rx*ux+Rz*uz,Ux*ux+Uz*uz,Bx*ux+Bz*uz,0
	addps		xmm1,xmm0				;xmm1 = Rx*ux+Ry*uy+Rz*uz,Ux*ux+Uy*uy+Uz*uz,Bx*ux+By*uy+Bz*uz,0
										;xmm1 = R.u,U.u,B.u,0
	movaps	[edx][10h],xmm1
;Fourth, find the position vector
	subps	xmm3,ViewPosition		;xmm3 = p-P
	movaps	xmm4,xmm3				;xmm4 = p-P
	movaps	xmm5,xmm3				;xmm5 = p-P
	mulps	xmm3,ViewInverse[00h]	;xmm3 = Rx*(px-Px),Ry*(py-Py),Rz*(pz-Pz),0
	mulps	xmm4,ViewInverse[10h]	;xmm4 = Ux*(px-Px),Uy*(py-Py),Uz*(pz-Pz),0
	mulps	xmm5,ViewInverse[20h]	;xmm5 = Bx*(px-Px),By*(py-Py),Bz*(pz-Pz),0

	movaps		xmm2,xmm3				;xmm2 = Rx*(px-Px),Ry*(py-Py),Rz*(pz-Pz),0
	unpckhps	xmm3,xmm5				;xmm3 = Rz*(pz-Pz),Bz*(pz-Pz),0,0
	unpcklps	xmm2,xmm5				;xmm2 = Rx*(px-Px),Bx*(px-Px),Ry*(py-Py),By*(py-Py)
	movaps		xmm5,xmm4				;xmm5 = Ux*(px-Px),Uy*(py-Py),Uz*(pz-Pz),0
	unpckhps	xmm4,xmm0				;xmm4 = Uz*(pz-Pz),0,0,0
	addps		xmm3,xmm2				;xmm3 = Rx*(px-Px)+Rz*(pz-Pz),Bx*(px-Px)+Bz*(pz-Pz),Ry*(py-Py),By*(py-Py)
	unpcklps	xmm5,xmm0				;xmm5 = Ux*(px-Px),0,Uy*(py-Py),0
	addps		xmm4,xmm5				;xmm4 = Ux*(px-Px)+Uz*(pz-Pz),0,Uy*(py-Py),0
	movaps		xmm0,xmm3				;xmm0 = Rx*(px-Px)+Rz*(pz-Pz),Bx*(px-Px)+Bz*(pz-Pz),Ry*(py-Py),By*(py-Py)
	unpckhps	xmm3,xmm4				;xmm3 = Ry*(py-Py),Uy*(py-Py),By*(py-Py),0
	unpcklps	xmm0,xmm4				;xmm0 = Rx*(px-Px)+Rz*(pz-Pz),Ux*(px-Px)+Uz*(pz-Pz),Bx*(px-Px)+Bz*(pz-Pz),0
	addps		xmm3,xmm0				;xmm3 = Rx*(px-Px)+Ry*(py-Py)+Rz*(pz-Pz),Ux*(px-Px)+Uy*(py-Py)+Uz*(pz-Pz),Bx*(px-Px)+By*(py-Py)+Bz*(pz-Pz),0
										;xmm3 = R.(p-P),U.(p-P),B.(p-P),0
;Last, swizzle the data so that the four vectors are transposed into columns
	movaps		xmm0,[edx][00h]		;xmm0 = R.r,U.r,B.r,0
									;xmm1 = R.u,U.u,B.u,0
	movaps		xmm2,[edx][20h]		;xmm2 = R.b,U.b,B.b,0
									;xmm3 = R.(p-P),U.(p-P),B.(p-P),0

	movaps		xmm4,xmm0			;xmm4 = R.r,U.r,B.r,0
	movaps		xmm5,xmm1			;xmm5 = R.u,U.u,B.u,0
	unpcklps	xmm0,xmm1			;xmm0 = R.r,R.u,U.r,U.u
	movhlps		xmm1,xmm0			;xmm1 = U.r,U.u,B.u,0
	movaps		xmm6,xmm2			;xmm6 = R.b,U.b,B.b,0
	unpcklps	xmm2,xmm3			;xmm2 = R.b,R.(p-P),U.b,U.(p-P)
	movlhps		xmm0,xmm2			;xmm0 = R.r,R.u,R.b,R.(p-P)
	movhlps		xmm2,xmm2			;xmm2 = U.b,U.(p-P),U.b,U.(p-P)
	movlhps		xmm1,xmm2			;xmm1 = U.r,U.u,U.b,U.(p-P)
	movaps		[edx][00h],xmm0
	movaps		[edx][10h],xmm1
	unpckhps	xmm4,xmm6			;xmm4 = B.r,B.b,0,0
	unpckhps	xmm5,xmm3			;xmm5 = B.u,B.(p-P),0,0
	unpcklps	xmm4,xmm5			;xmm4 = B.r,B.u,B.b,B.(p-P)
	movaps		[edx][20h],xmm4

	ret
InverseLookAtOriginSlow	endp

;>*******************************************************************************************************************************
;*																																*
;*	Function:	CalculateVelocity																								*
;*																																*
;*																																*
;*	Parameters:																													*
;*	xmm0	- This is the position of the object.																				*
;*	xmm6	- This is the current velocity of the object.																		*
;*	xmm7	- This is the object's energy (in float 0).																			*
;*																																*
;*	Returns:																													*
;*	xmm6	- the new velocity																									*
;*																																*
;<*******************************************************************************************************************************
CalculateVelocity	proc
	invoke	CalculateAcceleration	;Returns acceleration in xmm1 and negative of potential energy in float 0 of xmm0
									;It doesn't modify xmm6 or xmm7.
	addps	xmm1,xmm6				;xmm1 = new v
	movaps	xmm2,xmm1				;xmm2 = v
	movaps	xmm5,xmm1
	mulps	xmm1,xmm1				;xmm1 = v.v,v.v,v.v,v.v
	haddps	xmm1,xmm1				;
	haddps	xmm1,xmm1				;
	rsqrtps	xmm1,xmm1				;xmm1 = 1/|v|,1/|v|,1/|v|,1/|v|
	addss	xmm0,xmm7				;xmm0 = E_tot - E_p = E_k
	addss	xmm0,xmm0				;xmm0 = 2(E_tot - E_p) = |good v|^2
	rcpss	xmm3,xmm0				;xmm3 = 1/|good v|^2
	rsqrtss	xmm3,xmm3				;xmm3 = |good v|
	shufps	xmm3,xmm3,00000000b		;xmm3 = |good v|,|good v|,|good v|,|good v|
	mulps	xmm2,xmm1				;xmm2 = v/|v|
	mulps	xmm2,xmm3				;xmm2 = |good v|*v/|v| = v with length of good v
	movd	eax,xmm2
	movd	ecx,xmm0
	and		eax,7F800000h
	cmp		eax,7F800000h			;If the new velocity is NaN or infinite (exponent FF),
	je		AdjustForNaNOrInfinity	;don't adjust the velocity, so that the view leaves the critical point.
	movaps	xmm6,xmm2				;
	jmp		DoneUpdateVelocity
AdjustForNaNOrInfinity:
	cmp		ecx,0					;If to keep constant energy, the kinetic energy needs to be negative or zero,
	jg		DoneUpdateVelocity		;use the unadjusted velocity (xmm5), because it will lead back to the cube.
NeedNegativeOrZero:
	movaps	xmm6,xmm5
DoneUpdateVelocity:
	ret
CalculateVelocity	endp

;>*******************************************************************************************************************************
;*																																*
;*	Function:	CalculateVelocitySlow																							*
;*																																*
;*																																*
;*	Parameters:																													*
;*	xmm0	- This is the position of the object.																				*
;*	xmm6	- This is the current velocity of the object.																		*
;*	xmm7	- This is the object's energy (in float 0).																			*
;*																																*
;*	Returns:																													*
;*	xmm6	- the new velocity																									*
;*																																*
;<*******************************************************************************************************************************
CalculateVelocitySlow	proc
	invoke	CalculateAccelerationSlow	;Returns acceleration in xmm1 and negative of potential energy in float 0 of xmm0
									;It doesn't modify xmm6 or xmm7.
	addps	xmm1,xmm6				;xmm1 = new v
	movaps	xmm2,xmm1				;xmm2 = v
	movaps	xmm5,xmm1
	mulps	xmm1,xmm1				;xmm1 = v.v,v.v,v.v,v.v
	movhlps	xmm3,xmm1				;
	addps	xmm1,xmm3				;
	movss	xmm3,xmm1				;
	shufps	xmm1,xmm1,01b			;
	addss	xmm1,xmm3				;
	shufps	xmm1,xmm1,00000000b		;
	rsqrtps	xmm1,xmm1				;xmm1 = 1/|v|,1/|v|,1/|v|,1/|v|
	addss	xmm0,xmm7				;xmm0 = E_tot - E_p = E_k
	addss	xmm0,xmm0				;xmm0 = 2(E_tot - E_p) = |good v|^2
	rcpss	xmm3,xmm0				;xmm3 = 1/|good v|^2
	rsqrtss	xmm3,xmm3				;xmm3 = |good v|
	shufps	xmm3,xmm3,00000000b		;xmm3 = |good v|,|good v|,|good v|,|good v|
	mulps	xmm2,xmm1				;xmm2 = v/|v|
	mulps	xmm2,xmm3				;xmm2 = |good v|*v/|v| = v with length of good v
	movd	eax,xmm2
	movd	ecx,xmm0
	and		eax,7F800000h
	cmp		eax,7F800000h			;If the new velocity is NaN or infinite (exponent FF),
	je		AdjustForNaNOrInfinity	;don't adjust the velocity, so that the view leaves the critical point.
	movaps	xmm6,xmm2				;
	jmp		DoneUpdateVelocity
AdjustForNaNOrInfinity:
	cmp		ecx,0					;If to keep constant energy, the kinetic energy needs to be negative or zero,
	jg		DoneUpdateVelocity		;use the unadjusted velocity (xmm5), because it will lead back to the cube.
NeedNegativeOrZero:
	movaps	xmm6,xmm5
DoneUpdateVelocity:
	ret
CalculateVelocitySlow	endp

;>*******************************************************************************************************************************
;*																																*
;*	Function:	CalculateAcceleration																							*
;*																																*
;*	Calculates the acceleration based on the proximity to other objects.  This does not modify xmm6 or xmm7.					*
;*																																*
;*	Parameters:																													*
;*	xmm0	- This is the position of the object.																				*
;*																																*
;*	Returns:																													*
;*	xmm0	- float 0 is negative of potential energy																			*
;*	xmm1	- acceleration vector																								*
;*																																*
;<*******************************************************************************************************************************
CalculateAcceleration	proc
;First, accumulate the acceleration and energy from the neurons in the cube (positive charge).
	xor		eax,eax
	xorps	xmm1,xmm1						;xmm1 = 0
	xorps	xmm5,xmm5						;xmm5 = 0
NextNeuron:
	movaps	xmm2,NeuronCentrePoints[eax]	;xmm2 = pj
	add		eax,10h
	subps	xmm2,xmm0						;xmm2 = pj-p
	movaps	xmm3,xmm2						;xmm3 = pj-p
	mulps	xmm2,xmm2						;xmm2 = (pj-p).(pj-p),(pj-p).(pj-p),(pj-p).(pj-p),(pj-p).(pj-p)
	haddps	xmm2,xmm2						;
	haddps	xmm2,xmm2						;
	rsqrtps	xmm4,xmm2						;xmm4 = 1/|pj-p|,1/|pj-p|,1/|pj-p|,1/|pj-p|
	cmp		eax,NUM_CUBE_NEURONS*10h
	rcpps	xmm2,xmm2						;xmm2 = 1/|pj-p|^2,1/|pj-p|^2,1/|pj-p|^2,1/|pj-p|^2
	mulps	xmm3,xmm4						;xmm3 = (pj-p)/|pj-p|
	addss	xmm5,xmm4						;xmm5 += 1/|pj-p|
	mulps	xmm3,xmm2						;xmm3 = (pj-p)/|pj-p|^3
	addps	xmm1,xmm3						;xmm1 += (pj-p)/|pj-p|^3
	jne		NextNeuron

;Next, take into account acceleration and energy from the view (negative charge).
	movaps	xmm2,ViewPosition				;xmm2 = pj
	subps	xmm2,xmm0						;xmm2 = pj-p
	movaps	xmm3,xmm2						;xmm3 = pj-p
	mulps	xmm2,xmm2						;xmm2 = (pj-p).(pj-p),(pj-p).(pj-p),(pj-p).(pj-p),(pj-p).(pj-p)
	haddps	xmm2,xmm2						;
	haddps	xmm2,xmm2						;
	rsqrtps	xmm4,xmm2						;xmm4 = 1/|pj-p|,1/|pj-p|,1/|pj-p|,1/|pj-p|
	movd	eax,xmm4
	and		eax,7F800000h
	cmp		eax,7F800000h			;If the new velocity is NaN or infinite (exponent FF),
	je		AdjustForNaNOrInfinity	;don't take into account this point (they're probably the same object).
	rcpps	xmm2,xmm2						;xmm2 = 1/|pj-p|^2,1/|pj-p|^2,1/|pj-p|^2,1/|pj-p|^2
	mulps	xmm3,xmm4						;xmm3 = (pj-p)/|pj-p|
	subss	xmm5,xmm4						;xmm5 -= 1/|pj-p|
	mulps	xmm3,xmm2						;xmm3 = (pj-p)/|pj-p|^3
	subps	xmm1,xmm3						;xmm1 -= (pj-p)/|pj-p|^3
AdjustForNaNOrInfinity:

;Next, take into account acceleration and energy from the orbit A neuron (negative charge).
	movaps	xmm2,OrbitAPosition				;xmm2 = pj
	subps	xmm2,xmm0						;xmm2 = pj-p
	movaps	xmm3,xmm2						;xmm3 = pj-p
	mulps	xmm2,xmm2						;xmm2 = (pj-p).(pj-p),(pj-p).(pj-p),(pj-p).(pj-p),(pj-p).(pj-p)
	haddps	xmm2,xmm2						;
	haddps	xmm2,xmm2						;
	rsqrtps	xmm4,xmm2						;xmm4 = 1/|pj-p|,1/|pj-p|,1/|pj-p|,1/|pj-p|
	movd	eax,xmm4
	and		eax,7F800000h
	cmp		eax,7F800000h			;If the new velocity is NaN or infinite (exponent FF),
	je		AdjustForNaNOrInfinity2	;don't take into account this point (they're probably the same object).
	rcpps	xmm2,xmm2						;xmm2 = 1/|pj-p|^2,1/|pj-p|^2,1/|pj-p|^2,1/|pj-p|^2
	mulps	xmm3,xmm4						;xmm3 = (pj-p)/|pj-p|
	subss	xmm5,xmm4						;xmm5 -= 1/|pj-p|
	mulps	xmm3,xmm2						;xmm3 = (pj-p)/|pj-p|^3
	subps	xmm1,xmm3						;xmm1 -= (pj-p)/|pj-p|^3
AdjustForNaNOrInfinity2:


;Next, take into account acceleration and energy from the orbit B neuron (negative charge).
	movaps	xmm2,OrbitBPosition				;xmm2 = pj
	subps	xmm2,xmm0						;xmm2 = pj-p
	movaps	xmm3,xmm2						;xmm3 = pj-p
	mulps	xmm2,xmm2						;xmm2 = (pj-p).(pj-p),(pj-p).(pj-p),(pj-p).(pj-p),(pj-p).(pj-p)
	haddps	xmm2,xmm2						;
	haddps	xmm2,xmm2						;
	rsqrtps	xmm4,xmm2						;xmm4 = 1/|pj-p|,1/|pj-p|,1/|pj-p|,1/|pj-p|
	movd	eax,xmm4
	and		eax,7F800000h
	cmp		eax,7F800000h			;If the new velocity is NaN or infinite (exponent FF),
	je		AdjustForNaNOrInfinity3	;don't take into account this point (they're probably the same object).
	rcpps	xmm2,xmm2						;xmm2 = 1/|pj-p|^2,1/|pj-p|^2,1/|pj-p|^2,1/|pj-p|^2
	mulps	xmm3,xmm4						;xmm3 = (pj-p)/|pj-p|
	subss	xmm5,xmm4						;xmm5 -= 1/|pj-p|
	mulps	xmm3,xmm2						;xmm3 = (pj-p)/|pj-p|^3
	subps	xmm1,xmm3						;xmm1 -= (pj-p)/|pj-p|^3
AdjustForNaNOrInfinity3:

;Last, adjust for the force constant.
	movaps	xmm0,ForceConstant				;xmm0 = k,k,k,k
	mulps	xmm1,xmm0						;xmm1 = k*sum_j((pj-p)/|pj-p|^3)
	mulss	xmm0,xmm5						;xmm0 = k*sum_j(1/|pj-p|)

	ret
CalculateAcceleration	endp

;>*******************************************************************************************************************************
;*																																*
;*	Function:	CalculateAccelerationSlow																						*
;*																																*
;*	Calculates the acceleration based on the proximity to other objects.  This does not modify xmm6 or xmm7.					*
;*																																*
;*	Parameters:																													*
;*	xmm0	- This is the position of the object.																				*
;*																																*
;*	Returns:																													*
;*	xmm0	- float 0 is negative of potential energy																			*
;*	xmm1	- acceleration vector																								*
;*																																*
;<*******************************************************************************************************************************
CalculateAccelerationSlow	proc
;First, accumulate the acceleration and energy from the neurons in the cube (positive charge).
	xor		eax,eax
	xorps	xmm1,xmm1						;xmm1 = 0
	xorps	xmm5,xmm5						;xmm5 = 0
NextNeuron:
	movaps	xmm2,NeuronCentrePoints[eax]	;xmm2 = pj
	add		eax,10h
	subps	xmm2,xmm0						;xmm2 = pj-p
	movaps	xmm3,xmm2						;xmm3 = pj-p
	mulps	xmm2,xmm2						;xmm2 = (pj-p).(pj-p),(pj-p).(pj-p),(pj-p).(pj-p),(pj-p).(pj-p)
	movhlps	xmm4,xmm2						;
	addps	xmm2,xmm4						;
	movss	xmm4,xmm2						;
	shufps	xmm2,xmm2,01b					;
	addss	xmm2,xmm4						;
	shufps	xmm2,xmm2,00000000b				;
	rsqrtps	xmm4,xmm2						;xmm4 = 1/|pj-p|,1/|pj-p|,1/|pj-p|,1/|pj-p|
	cmp		eax,NUM_CUBE_NEURONS*10h
	rcpps	xmm2,xmm2						;xmm2 = 1/|pj-p|^2,1/|pj-p|^2,1/|pj-p|^2,1/|pj-p|^2
	mulps	xmm3,xmm4						;xmm3 = (pj-p)/|pj-p|
	addss	xmm5,xmm4						;xmm5 += 1/|pj-p|
	mulps	xmm3,xmm2						;xmm3 = (pj-p)/|pj-p|^3
	addps	xmm1,xmm3						;xmm1 += (pj-p)/|pj-p|^3
	jne		NextNeuron

;Next, take into account acceleration and energy from the view (negative charge).
	movaps	xmm2,ViewPosition				;xmm2 = pj
	subps	xmm2,xmm0						;xmm2 = pj-p
	movaps	xmm3,xmm2						;xmm3 = pj-p
	mulps	xmm2,xmm2						;xmm2 = (pj-p).(pj-p),(pj-p).(pj-p),(pj-p).(pj-p),(pj-p).(pj-p)
	movhlps	xmm4,xmm2						;
	addps	xmm2,xmm4						;
	movss	xmm4,xmm2						;
	shufps	xmm2,xmm2,01b					;
	addss	xmm2,xmm4						;
	shufps	xmm2,xmm2,00000000b				;
	rsqrtps	xmm4,xmm2						;xmm4 = 1/|pj-p|,1/|pj-p|,1/|pj-p|,1/|pj-p|
	movd	eax,xmm4
	and		eax,7F800000h
	cmp		eax,7F800000h			;If the new velocity is NaN or infinite (exponent FF),
	je		AdjustForNaNOrInfinity	;don't take into account this point (they're probably the same object).
	rcpps	xmm2,xmm2						;xmm2 = 1/|pj-p|^2,1/|pj-p|^2,1/|pj-p|^2,1/|pj-p|^2
	mulps	xmm3,xmm4						;xmm3 = (pj-p)/|pj-p|
	subss	xmm5,xmm4						;xmm5 -= 1/|pj-p|
	mulps	xmm3,xmm2						;xmm3 = (pj-p)/|pj-p|^3
	subps	xmm1,xmm3						;xmm1 -= (pj-p)/|pj-p|^3
AdjustForNaNOrInfinity:

;Next, take into account acceleration and energy from the orbit A neuron (negative charge).
	movaps	xmm2,OrbitAPosition				;xmm2 = pj
	subps	xmm2,xmm0						;xmm2 = pj-p
	movaps	xmm3,xmm2						;xmm3 = pj-p
	mulps	xmm2,xmm2						;xmm2 = (pj-p).(pj-p),(pj-p).(pj-p),(pj-p).(pj-p),(pj-p).(pj-p)
	movhlps	xmm4,xmm2						;
	addps	xmm2,xmm4						;
	movss	xmm4,xmm2						;
	shufps	xmm2,xmm2,01b					;
	addss	xmm2,xmm4						;
	shufps	xmm2,xmm2,00000000b				;
	rsqrtps	xmm4,xmm2						;xmm4 = 1/|pj-p|,1/|pj-p|,1/|pj-p|,1/|pj-p|
	movd	eax,xmm4
	and		eax,7F800000h
	cmp		eax,7F800000h			;If the new velocity is NaN or infinite (exponent FF),
	je		AdjustForNaNOrInfinity2	;don't take into account this point (they're probably the same object).
	rcpps	xmm2,xmm2						;xmm2 = 1/|pj-p|^2,1/|pj-p|^2,1/|pj-p|^2,1/|pj-p|^2
	mulps	xmm3,xmm4						;xmm3 = (pj-p)/|pj-p|
	subss	xmm5,xmm4						;xmm5 -= 1/|pj-p|
	mulps	xmm3,xmm2						;xmm3 = (pj-p)/|pj-p|^3
	subps	xmm1,xmm3						;xmm1 -= (pj-p)/|pj-p|^3
AdjustForNaNOrInfinity2:

;Next, take into account acceleration and energy from the orbit B neuron (negative charge).
	movaps	xmm2,OrbitBPosition				;xmm2 = pj
	subps	xmm2,xmm0						;xmm2 = pj-p
	movaps	xmm3,xmm2						;xmm3 = pj-p
	mulps	xmm2,xmm2						;xmm2 = (pj-p).(pj-p),(pj-p).(pj-p),(pj-p).(pj-p),(pj-p).(pj-p)
	movhlps	xmm4,xmm2						;
	addps	xmm2,xmm4						;
	movss	xmm4,xmm2						;
	shufps	xmm2,xmm2,01b					;
	addss	xmm2,xmm4						;
	shufps	xmm2,xmm2,00000000b				;
	rsqrtps	xmm4,xmm2						;xmm4 = 1/|pj-p|,1/|pj-p|,1/|pj-p|,1/|pj-p|
	movd	eax,xmm4
	and		eax,7F800000h
	cmp		eax,7F800000h			;If the new velocity is NaN or infinite (exponent FF),
	je		AdjustForNaNOrInfinity3	;don't take into account this point (they're probably the same object).
	rcpps	xmm2,xmm2						;xmm2 = 1/|pj-p|^2,1/|pj-p|^2,1/|pj-p|^2,1/|pj-p|^2
	mulps	xmm3,xmm4						;xmm3 = (pj-p)/|pj-p|
	subss	xmm5,xmm4						;xmm5 -= 1/|pj-p|
	mulps	xmm3,xmm2						;xmm3 = (pj-p)/|pj-p|^3
	subps	xmm1,xmm3						;xmm1 -= (pj-p)/|pj-p|^3
AdjustForNaNOrInfinity3:

;Last, adjust for the force constant.
	movaps	xmm0,ForceConstant				;xmm0 = k,k,k,k
	mulps	xmm1,xmm0						;xmm1 = k*sum_j((pj-p)/|pj-p|^3)
	mulss	xmm0,xmm5						;xmm0 = k*sum_j(1/|pj-p|)

	ret
CalculateAccelerationSlow	endp


